OSDN Git Service

LinGui: remove target file size option
[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-2011  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 "subtitlehandler.h"
34 #include "audiohandler.h"
35 #include "x264handler.h"
36 #include "preview.h"
37 #include "values.h"
38 #include "lang.h"
39
40 typedef struct
41 {
42         const gchar *option;
43         const gchar *shortOpt;
44         gdouble ivalue;
45         const gchar *svalue;
46 } options_map_t;
47
48 typedef struct
49 {
50         gint count;
51         options_map_t *map;
52 } combo_opts_t;
53
54 static gchar **index_str = NULL;
55 static gint index_str_size = 0;
56
57 static void 
58 index_str_init(gint max_index)
59 {
60         int ii;
61
62         if (max_index+1 > index_str_size)
63         {
64                 index_str = realloc(index_str, (max_index+1) * sizeof(char*));
65                 for (ii = index_str_size; ii <= max_index; ii++)
66                 {
67                         index_str[ii] = g_strdup_printf("%d", ii);
68                 }
69                 index_str_size = max_index + 1;
70         }
71 }
72
73 static options_map_t d_point_to_point_opts[] =
74 {
75         {"Chapters:",       "chapter", 0, "0"},
76         {"Seconds:", "time",    1, "1"},
77         {"Frames:",   "frame",   2, "2"},
78 };
79 combo_opts_t point_to_point_opts =
80 {
81         sizeof(d_point_to_point_opts)/sizeof(options_map_t),
82         d_point_to_point_opts
83 };
84
85 static options_map_t d_when_complete_opts[] =
86 {
87         {"Do Nothing",            "nothing",  0, "0"},
88         {"Show Notification",     "notify",   1, "1"},
89         {"Quit Handbrake",        "quit",     4, "4"},
90         {"Put Computer To Sleep", "sleep",    2, "2"},
91         {"Shutdown Computer",     "shutdown", 3, "3"},
92 };
93 combo_opts_t when_complete_opts =
94 {
95         sizeof(d_when_complete_opts)/sizeof(options_map_t),
96         d_when_complete_opts
97 };
98
99 static options_map_t d_par_opts[] =
100 {
101         {"Off", "0", 0, "0"},
102         {"Strict", "1", 1, "1"},
103         {"Loose", "2", 2, "2"},
104         {"Custom", "3", 3, "3"},
105 };
106 combo_opts_t par_opts =
107 {
108         sizeof(d_par_opts)/sizeof(options_map_t),
109         d_par_opts
110 };
111
112 static options_map_t d_alignment_opts[] =
113 {
114         {"2", "2", 2, "2"},
115         {"4", "4", 4, "4"},
116         {"8", "8", 8, "8"},
117         {"16", "16", 16, "16"},
118 };
119 combo_opts_t alignment_opts =
120 {
121         sizeof(d_alignment_opts)/sizeof(options_map_t),
122         d_alignment_opts
123 };
124
125 static options_map_t d_logging_opts[] =
126 {
127         {"0", "0", 0, "0"},
128         {"1", "1", 1, "1"},
129         {"2", "2", 2, "2"},
130 };
131 combo_opts_t logging_opts =
132 {
133         sizeof(d_logging_opts)/sizeof(options_map_t),
134         d_logging_opts
135 };
136
137 static options_map_t d_log_longevity_opts[] =
138 {
139         {"Week",     "week",     7, "7"},
140         {"Month",    "month",    30, "30"},
141         {"Year",     "year",     365, "365"},
142         {"Immortal", "immortal", 366, "366"},
143 };
144 combo_opts_t log_longevity_opts =
145 {
146         sizeof(d_log_longevity_opts)/sizeof(options_map_t),
147         d_log_longevity_opts
148 };
149
150 static options_map_t d_appcast_update_opts[] =
151 {
152         {"Never", "never", 0, "never"},
153         {"Daily", "daily", 1, "daily"},
154         {"Weekly", "weekly", 2, "weekly"},
155         {"Monthly", "monthly", 3, "monthly"},
156 };
157 combo_opts_t appcast_update_opts =
158 {
159         sizeof(d_appcast_update_opts)/sizeof(options_map_t),
160         d_appcast_update_opts
161 };
162
163 static options_map_t d_vqual_granularity_opts[] =
164 {
165         {"0.2",  "0.2",  0.2,  "0.2"},
166         {"0.25", "0.25", 0.25, "0.25"},
167         {"0.5",  "0.5",  0.5,  "0.5"},
168         {"1",    "1",    1,    "1"},
169 };
170 combo_opts_t vqual_granularity_opts =
171 {
172         sizeof(d_vqual_granularity_opts)/sizeof(options_map_t),
173         d_vqual_granularity_opts
174 };
175
176 static options_map_t d_container_opts[] =
177 {
178         {"MKV", "mkv", HB_MUX_MKV, "mkv"},
179         {"MP4", "mp4", HB_MUX_MP4, "mp4"},
180 };
181 combo_opts_t container_opts =
182 {
183         sizeof(d_container_opts)/sizeof(options_map_t),
184         d_container_opts
185 };
186
187 static options_map_t d_detel_opts[] =
188 {
189         {"Off",    "off",   0, ""},
190         {"Custom", "custom", 1, ""},
191         {"Default","default",2, NULL},
192 };
193 combo_opts_t detel_opts =
194 {
195         sizeof(d_detel_opts)/sizeof(options_map_t),
196         d_detel_opts
197 };
198
199 static options_map_t d_decomb_opts[] =
200 {
201         {"Off",    "off",   0, ""},
202         {"Custom", "custom", 1, ""},
203         {"Default","default",2, NULL},
204 };
205 combo_opts_t decomb_opts =
206 {
207         sizeof(d_decomb_opts)/sizeof(options_map_t),
208         d_decomb_opts
209 };
210
211 static options_map_t d_deint_opts[] =
212 {
213         {"Off",    "off",   0, ""},
214         {"Custom", "custom", 1, ""},
215         {"Fast",   "fast",   2, "-1:-1:-1:0:1"},
216         {"Slow",   "slow",   3, "2:-1:-1:0:1"},
217         {"Slower", "slower", 4, "0:-1:-1:0:1"},
218 };
219 combo_opts_t deint_opts =
220 {
221         sizeof(d_deint_opts)/sizeof(options_map_t),
222         d_deint_opts
223 };
224
225 static options_map_t d_denoise_opts[] =
226 {
227         {"Off",    "off",   0, ""},
228         {"Custom", "custom", 1, ""},
229         {"Weak",   "weak",   2, "2:1:2:3"},
230         {"Medium", "medium", 3, "3:2:2:3"},
231         {"Strong", "strong", 4, "7:7:5:5"},
232 };
233 combo_opts_t denoise_opts =
234 {
235         sizeof(d_denoise_opts)/sizeof(options_map_t),
236         d_denoise_opts
237 };
238
239 static options_map_t d_vcodec_opts[] =
240 {
241         {"H.264 (x264)",    "x264",   HB_VCODEC_X264, ""},
242         {"MPEG-4 (FFmpeg)", "ffmpeg", HB_VCODEC_FFMPEG, ""},
243         {"VP3 (Theora)",    "theora", HB_VCODEC_THEORA, ""},
244 };
245 combo_opts_t vcodec_opts =
246 {
247         sizeof(d_vcodec_opts)/sizeof(options_map_t),
248         d_vcodec_opts
249 };
250
251 static options_map_t d_acodec_opts[] =
252 {
253         {"AAC (faac)",      "faac",    HB_ACODEC_FAAC,     "faac"},
254         {"MP3 (lame)",      "lame",    HB_ACODEC_LAME,     "lame"},
255         {"Vorbis",          "vorbis",  HB_ACODEC_VORBIS,   "vorbis"},
256         {"AC3 (ffmpeg)",    "ac3",     HB_ACODEC_AC3,      "ac3"},
257         {"AC3 (pass-thru)", "ac3pass", HB_ACODEC_AC3_PASS, "ac3pass"},
258         {"DTS (pass-thru)", "dtspass", HB_ACODEC_DCA_PASS, "dtspass"},
259         {"Choose For Me",   "auto",    HB_ACODEC_ANY,      "auto"},
260 };
261 combo_opts_t acodec_opts =
262 {
263         sizeof(d_acodec_opts)/sizeof(options_map_t),
264         d_acodec_opts
265 };
266
267 static options_map_t d_direct_opts[] =
268 {
269         {"None",      "none",     0, "none"},
270         {"Spatial",   "spatial",  1, "spatial"},
271         {"Temporal",  "temporal", 2, "temporal"},
272         {"Automatic", "auto",     3, "auto"},
273 };
274 combo_opts_t direct_opts =
275 {
276         sizeof(d_direct_opts)/sizeof(options_map_t),
277         d_direct_opts
278 };
279
280 static options_map_t d_badapt_opts[] =
281 {
282         {"Off",             "0", 0, "0"},
283         {"Fast",            "1", 1, "1"},
284         {"Optimal",         "2", 2, "2"},
285 };
286 combo_opts_t badapt_opts =
287 {
288         sizeof(d_badapt_opts)/sizeof(options_map_t),
289         d_badapt_opts
290 };
291
292 static options_map_t d_bpyramid_opts[] =
293 {
294         {"Off",    "none",   0, "none"},
295         {"Strict", "strict", 1, "strict"},
296         {"Normal", "normal", 2, "normal"},
297 };
298 combo_opts_t bpyramid_opts =
299 {
300         sizeof(d_bpyramid_opts)/sizeof(options_map_t),
301         d_bpyramid_opts
302 };
303
304 static options_map_t d_weightp_opts[] =
305 {
306         {"Off",    "0", 0, "0"},
307         {"Simple", "1", 1, "1"},
308         {"Smart",  "2", 2, "2"},
309 };
310 combo_opts_t weightp_opts =
311 {
312         sizeof(d_weightp_opts)/sizeof(options_map_t),
313         d_weightp_opts
314 };
315
316 static options_map_t d_me_opts[] =
317 {
318         {"Diamond",              "dia",  0, "dia"},
319         {"Hexagon",              "hex",  1, "hex"},
320         {"Uneven Multi-Hexagon", "umh",  2, "umh"},
321         {"Exhaustive",           "esa",  3, "esa"},
322         {"Hadamard Exhaustive",  "tesa", 4, "tesa"},
323 };
324 combo_opts_t me_opts =
325 {
326         sizeof(d_me_opts)/sizeof(options_map_t),
327         d_me_opts
328 };
329
330 static options_map_t d_subme_opts[] =
331 {
332         {"0: SAD, no subpel",          "0", 0, "0"},
333         {"1: SAD, qpel",               "1", 1, "1"},
334         {"2: SATD, qpel",              "2", 2, "2"},
335         {"3: SATD: multi-qpel",        "3", 3, "3"},
336         {"4: SATD, qpel on all",       "4", 4, "4"},
337         {"5: SATD, multi-qpel on all", "5", 5, "5"},
338         {"6: RD in I/P-frames",        "6", 6, "6"},
339         {"7: RD in all frames",        "7", 7, "7"},
340         {"8: RD refine in I/P-frames", "8", 8, "8"},
341         {"9: RD refine in all frames", "9", 9, "9"},
342         {"10: QPRD in all frames",     "10", 10, "10"},
343 };
344 combo_opts_t subme_opts =
345 {
346         sizeof(d_subme_opts)/sizeof(options_map_t),
347         d_subme_opts
348 };
349
350 static options_map_t d_analyse_opts[] =
351 {
352         {"Most", "p8x8,b8x8,i8x8,i4x4", 0, "p8x8,b8x8,i8x8,i4x4"},
353         {"None", "none", 1, "none"},
354         {"Some", "i4x4,i8x8", 2, "i4x4,i8x8"},
355         {"All",  "all",  3, "all"},
356         {"Custom",  "custom",  4, "all"},
357 };
358 combo_opts_t analyse_opts =
359 {
360         sizeof(d_analyse_opts)/sizeof(options_map_t),
361         d_analyse_opts
362 };
363
364 static options_map_t d_trellis_opts[] =
365 {
366         {"Off",         "0", 0, "0"},
367         {"Encode only", "1", 1, "1"},
368         {"Always",      "2", 2, "2"},
369 };
370 combo_opts_t trellis_opts =
371 {
372         sizeof(d_trellis_opts)/sizeof(options_map_t),
373         d_trellis_opts
374 };
375
376 combo_opts_t subtitle_opts =
377 {
378         0,
379         NULL
380 };
381
382 combo_opts_t title_opts =
383 {
384         0,
385         NULL
386 };
387
388 combo_opts_t audio_track_opts =
389 {
390         0,
391         NULL
392 };
393
394 typedef struct
395 {
396         const gchar *name;
397         combo_opts_t *opts;
398 } combo_name_map_t;
399
400 combo_name_map_t combo_name_map[] =
401 {
402         {"PtoPType", &point_to_point_opts},
403         {"WhenComplete", &when_complete_opts},
404         {"PicturePAR", &par_opts},
405         {"PictureModulus", &alignment_opts},
406         {"LoggingLevel", &logging_opts},
407         {"LogLongevity", &log_longevity_opts},
408         {"check_updates", &appcast_update_opts},
409         {"VideoQualityGranularity", &vqual_granularity_opts},
410         {"FileFormat", &container_opts},
411         {"PictureDeinterlace", &deint_opts},
412         {"PictureDecomb", &decomb_opts},
413         {"PictureDetelecine", &detel_opts},
414         {"PictureDenoise", &denoise_opts},
415         {"VideoEncoder", &vcodec_opts},
416         {"AudioEncoder", &acodec_opts},
417         {"AudioEncoderActual", &acodec_opts},
418         {"x264_direct", &direct_opts},
419         {"x264_b_adapt", &badapt_opts},
420         {"x264_bpyramid", &bpyramid_opts},
421         {"x264_weighted_pframes", &weightp_opts},
422         {"x264_me", &me_opts},
423         {"x264_subme", &subme_opts},
424         {"x264_analyse", &analyse_opts},
425         {"x264_trellis", &trellis_opts},
426         {"SubtitleTrack", &subtitle_opts},
427         {"title", &title_opts},
428         {"AudioTrack", &audio_track_opts},
429         {NULL, NULL}
430 };
431
432 const gchar *srt_codeset_table[] =
433 {
434         "ANSI_X3.4-1968",
435         "ANSI_X3.4-1986",
436         "ANSI_X3.4",
437         "ANSI_X3.110-1983",
438         "ANSI_X3.110",
439         "ASCII",
440         "ECMA-114",
441         "ECMA-118",
442         "ECMA-128",
443         "ECMA-CYRILLIC",
444         "IEC_P27-1",
445         "ISO-8859-1",
446         "ISO-8859-2",
447         "ISO-8859-3",
448         "ISO-8859-4",
449         "ISO-8859-5",
450         "ISO-8859-6",
451         "ISO-8859-7",
452         "ISO-8859-8",
453         "ISO-8859-9",
454         "ISO-8859-9E",
455         "ISO-8859-10",
456         "ISO-8859-11",
457         "ISO-8859-13",
458         "ISO-8859-14",
459         "ISO-8859-15",
460         "ISO-8859-16",
461         "UTF-7",
462         "UTF-8",
463         "UTF-16",
464         "UTF-16LE",
465         "UTF-16BE",
466         "UTF-32",
467         "UTF-32LE",
468         "UTF-32BE",
469         NULL
470 };
471 #define SRT_TABLE_SIZE (sizeof(srt_codeset_table)/ sizeof(char*)-1)
472
473 #if 0
474 typedef struct iso639_lang_t
475 {
476     char * eng_name;        /* Description in English */
477     char * native_name;     /* Description in native language */
478     char * iso639_1;       /* ISO-639-1 (2 characters) code */
479     char * iso639_2;        /* ISO-639-2/t (3 character) code */
480     char * iso639_2b;       /* ISO-639-2/b code (if different from above) */
481 } iso639_lang_t;
482 #endif
483
484 const iso639_lang_t ghb_language_table[] =
485
486         { "Any", "", "zz", "und" },
487         { "Afar", "", "aa", "aar" },
488         { "Abkhazian", "", "ab", "abk" },
489         { "Afrikaans", "", "af", "afr" },
490         { "Akan", "", "ak", "aka" },
491         { "Albanian", "", "sq", "sqi", "alb" },
492         { "Amharic", "", "am", "amh" },
493         { "Arabic", "", "ar", "ara" },
494         { "Aragonese", "", "an", "arg" },
495         { "Armenian", "", "hy", "hye", "arm" },
496         { "Assamese", "", "as", "asm" },
497         { "Avaric", "", "av", "ava" },
498         { "Avestan", "", "ae", "ave" },
499         { "Aymara", "", "ay", "aym" },
500         { "Azerbaijani", "", "az", "aze" },
501         { "Bashkir", "", "ba", "bak" },
502         { "Bambara", "", "bm", "bam" },
503         { "Basque", "", "eu", "eus", "baq" },
504         { "Belarusian", "", "be", "bel" },
505         { "Bengali", "", "bn", "ben" },
506         { "Bihari", "", "bh", "bih" },
507         { "Bislama", "", "bi", "bis" },
508         { "Bosnian", "", "bs", "bos" },
509         { "Breton", "", "br", "bre" },
510         { "Bulgarian", "", "bg", "bul" },
511         { "Burmese", "", "my", "mya", "bur" },
512         { "Catalan", "", "ca", "cat" },
513         { "Chamorro", "", "ch", "cha" },
514         { "Chechen", "", "ce", "che" },
515         { "Chinese", "", "zh", "zho", "chi" },
516         { "Church Slavic", "", "cu", "chu" },
517         { "Chuvash", "", "cv", "chv" },
518         { "Cornish", "", "kw", "cor" },
519         { "Corsican", "", "co", "cos" },
520         { "Cree", "", "cr", "cre" },
521         { "Czech", "", "cs", "ces", "cze" },
522         { "Danish", "Dansk", "da", "dan" },
523         { "German", "Deutsch", "de", "deu", "ger" },
524         { "Divehi", "", "dv", "div" },
525         { "Dzongkha", "", "dz", "dzo" },
526         { "English", "English", "en", "eng" },
527         { "Spanish", "Espanol", "es", "spa" },
528         { "Esperanto", "", "eo", "epo" },
529         { "Estonian", "", "et", "est" },
530         { "Ewe", "", "ee", "ewe" },
531         { "Faroese", "", "fo", "fao" },
532         { "Fijian", "", "fj", "fij" },
533         { "French", "Francais", "fr", "fra", "fre" },
534         { "Western Frisian", "", "fy", "fry" },
535         { "Fulah", "", "ff", "ful" },
536         { "Georgian", "", "ka", "kat", "geo" },
537         { "Gaelic (Scots)", "", "gd", "gla" },
538         { "Irish", "", "ga", "gle" },
539         { "Galician", "", "gl", "glg" },
540         { "Manx", "", "gv", "glv" },
541         { "Greek, Modern", "", "el", "ell", "gre" },
542         { "Guarani", "", "gn", "grn" },
543         { "Gujarati", "", "gu", "guj" },
544         { "Haitian", "", "ht", "hat" },
545         { "Hausa", "", "ha", "hau" },
546         { "Hebrew", "", "he", "heb" },
547         { "Herero", "", "hz", "her" },
548         { "Hindi", "", "hi", "hin" },
549         { "Hiri Motu", "", "ho", "hmo" },
550         { "Croatian", "Hrvatski", "hr", "hrv", "scr" },
551         { "Igbo", "", "ig", "ibo" },
552         { "Ido", "", "io", "ido" },
553         { "Icelandic", "Islenska", "is", "isl", "ice" },
554         { "Sichuan Yi", "", "ii", "iii" },
555         { "Inuktitut", "", "iu", "iku" },
556         { "Interlingue", "", "ie", "ile" },
557         { "Interlingua", "", "ia", "ina" },
558         { "Indonesian", "", "id", "ind" },
559         { "Inupiaq", "", "ik", "ipk" },
560         { "Italian", "Italiano", "it", "ita" },
561         { "Javanese", "", "jv", "jav" },
562         { "Japanese", "", "ja", "jpn" },
563         { "Kalaallisut", "", "kl", "kal" },
564         { "Kannada", "", "kn", "kan" },
565         { "Kashmiri", "", "ks", "kas" },
566         { "Kanuri", "", "kr", "kau" },
567         { "Kazakh", "", "kk", "kaz" },
568         { "Central Khmer", "", "km", "khm" },
569         { "Kikuyu", "", "ki", "kik" },
570         { "Kinyarwanda", "", "rw", "kin" },
571         { "Kirghiz", "", "ky", "kir" },
572         { "Komi", "", "kv", "kom" },
573         { "Kongo", "", "kg", "kon" },
574         { "Korean", "", "ko", "kor" },
575         { "Kuanyama", "", "kj", "kua" },
576         { "Kurdish", "", "ku", "kur" },
577         { "Lao", "", "lo", "lao" },
578         { "Latin", "", "la", "lat" },
579         { "Latvian", "", "lv", "lav" },
580         { "Limburgan", "", "li", "lim" },
581         { "Lingala", "", "ln", "lin" },
582         { "Lithuanian", "", "lt", "lit" },
583         { "Luxembourgish", "", "lb", "ltz" },
584         { "Luba-Katanga", "", "lu", "lub" },
585         { "Ganda", "", "lg", "lug" },
586         { "Macedonian", "", "mk", "mkd", "mac" },
587         { "Hungarian", "Magyar", "hu", "hun" },
588         { "Marshallese", "", "mh", "mah" },
589         { "Malayalam", "", "ml", "mal" },
590         { "Maori", "", "mi", "mri", "mao" },
591         { "Marathi", "", "mr", "mar" },
592         { "Malay", "", "ms", "msa", "msa" },
593         { "Malagasy", "", "mg", "mlg" },
594         { "Maltese", "", "mt", "mlt" },
595         { "Moldavian", "", "mo", "mol" },
596         { "Mongolian", "", "mn", "mon" },
597         { "Nauru", "", "na", "nau" },
598         { "Navajo", "", "nv", "nav" },
599         { "Dutch", "Nederlands", "nl", "nld", "dut" },
600         { "Ndebele, South", "", "nr", "nbl" },
601         { "Ndebele, North", "", "nd", "nde" },
602         { "Ndonga", "", "ng", "ndo" },
603         { "Nepali", "", "ne", "nep" },
604         { "Norwegian", "Norsk", "no", "nor" },
605         { "Norwegian Nynorsk", "", "nn", "nno" },
606         { "Norwegian Bokmål", "", "nb", "nob" },
607         { "Chichewa; Nyanja", "", "ny", "nya" },
608         { "Occitan", "", "oc", "oci" },
609         { "Ojibwa", "", "oj", "oji" },
610         { "Oriya", "", "or", "ori" },
611         { "Oromo", "", "om", "orm" },
612         { "Ossetian", "", "os", "oss" },
613         { "Panjabi", "", "pa", "pan" },
614         { "Persian", "", "fa", "fas", "per" },
615         { "Pali", "", "pi", "pli" },
616         { "Polish", "", "pl", "pol" },
617         { "Portuguese", "Portugues", "pt", "por" },
618         { "Pushto", "", "ps", "pus" },
619         { "Quechua", "", "qu", "que" },
620         { "Romansh", "", "rm", "roh" },
621         { "Romanian", "", "ro", "ron", "rum" },
622         { "Rundi", "", "rn", "run" },
623         { "Russian", "", "ru", "rus" },
624         { "Sango", "", "sg", "sag" },
625         { "Sanskrit", "", "sa", "san" },
626         { "Serbian", "", "sr", "srp", "scc" },
627         { "Sinhala", "", "si", "sin" },
628         { "Slovak", "", "sk", "slk", "slo" },
629         { "Slovenian", "", "sl", "slv" },
630         { "Northern Sami", "", "se", "sme" },
631         { "Samoan", "", "sm", "smo" },
632         { "Shona", "", "sn", "sna" },
633         { "Sindhi", "", "sd", "snd" },
634         { "Somali", "", "so", "som" },
635         { "Sotho, Southern", "", "st", "sot" },
636         { "Sardinian", "", "sc", "srd" },
637         { "Swati", "", "ss", "ssw" },
638         { "Sundanese", "", "su", "sun" },
639         { "Finnish", "Suomi", "fi", "fin" },
640         { "Swahili", "", "sw", "swa" },
641         { "Swedish", "Svenska", "sv", "swe" },
642         { "Tahitian", "", "ty", "tah" },
643         { "Tamil", "", "ta", "tam" },
644         { "Tatar", "", "tt", "tat" },
645         { "Telugu", "", "te", "tel" },
646         { "Tajik", "", "tg", "tgk" },
647         { "Tagalog", "", "tl", "tgl" },
648         { "Thai", "", "th", "tha" },
649         { "Tibetan", "", "bo", "bod", "tib" },
650         { "Tigrinya", "", "ti", "tir" },
651         { "Tonga", "", "to", "ton" },
652         { "Tswana", "", "tn", "tsn" },
653         { "Tsonga", "", "ts", "tso" },
654         { "Turkmen", "", "tk", "tuk" },
655         { "Turkish", "", "tr", "tur" },
656         { "Twi", "", "tw", "twi" },
657         { "Uighur", "", "ug", "uig" },
658         { "Ukrainian", "", "uk", "ukr" },
659         { "Urdu", "", "ur", "urd" },
660         { "Uzbek", "", "uz", "uzb" },
661         { "Venda", "", "ve", "ven" },
662         { "Vietnamese", "", "vi", "vie" },
663         { "Volapük", "", "vo", "vol" },
664         { "Welsh", "", "cy", "cym", "wel" },
665         { "Walloon", "", "wa", "wln" },
666         { "Wolof", "", "wo", "wol" },
667         { "Xhosa", "", "xh", "xho" },
668         { "Yiddish", "", "yi", "yid" },
669         { "Yoruba", "", "yo", "yor" },
670         { "Zhuang", "", "za", "zha" },
671         { "Zulu", "", "zu", "zul" },
672         {NULL, NULL, NULL, NULL}
673 };
674 #define LANG_TABLE_SIZE (sizeof(ghb_language_table)/ sizeof(iso639_lang_t)-1)
675
676 static void audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name);
677
678 static void
679 del_tree(const gchar *name, gboolean del_top)
680 {
681         const gchar *file;
682
683         if (g_file_test(name, G_FILE_TEST_IS_DIR))
684         {
685                 GDir *gdir = g_dir_open(name, 0, NULL);
686                 file = g_dir_read_name(gdir);
687                 while (file)
688                 {
689                         gchar *path;
690                         path = g_strdup_printf("%s/%s", name, file);
691                         del_tree(path, TRUE);
692                         g_free(path);
693                         file = g_dir_read_name(gdir);
694                 }
695                 if (del_top)
696                         g_rmdir(name);
697                 g_dir_close(gdir);
698         }
699         else
700         {
701                 g_unlink(name);
702         }
703 }
704
705 const gchar*
706 ghb_version()
707 {
708         return hb_get_version(NULL);
709 }
710
711 void
712 ghb_vquality_range(
713         signal_user_data_t *ud, 
714         gdouble *min, 
715         gdouble *max,
716         gdouble *step,
717         gdouble *page,
718         gint *digits,
719         gboolean *inverted)
720 {
721         gint vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
722         *page = 10;
723         *digits = 0;
724         switch (vcodec)
725         {
726                 case HB_VCODEC_X264:
727                 {
728                         *min = 0;
729                         *max = 51;
730                         *step = ghb_settings_combo_double(ud->settings, 
731                                                                                         "VideoQualityGranularity");
732                         if (*step == 0.2 || *step == 0.5)
733                                 *digits = 1;
734                         else if (*step == 0.25)
735                                 *digits = 2;
736                         *inverted = TRUE;
737                 } break;
738
739                 case HB_VCODEC_FFMPEG:
740                 {
741                         *min = 1;
742                         *max = 31;
743                         *step = 1;
744                         *inverted = TRUE;
745                 } break;
746
747                 case HB_VCODEC_THEORA:
748                 {
749                         *min = 0;
750                         *max = 63;
751                         *step = 1;
752                         *inverted = FALSE;
753                 } break;
754
755                 default:
756                 {
757                         *min = 0;
758                         *max = 100;
759                         *step = 1;
760                         *inverted = FALSE;
761                 } break;
762         }
763 }
764
765 gint
766 find_combo_entry(combo_opts_t *opts, const GValue *gval)
767 {
768         gint ii;
769
770         if (G_VALUE_TYPE(gval) == G_TYPE_STRING)
771         {
772                 gchar *str;
773                 str = ghb_value_string(gval);
774                 for (ii = 0; ii < opts->count; ii++)
775                 {
776                         if (strcmp(opts->map[ii].shortOpt, str) == 0)
777                         {
778                                 break;
779                         }
780                 }
781                 g_free(str);
782                 return ii;
783         }
784         else if (G_VALUE_TYPE(gval) == G_TYPE_DOUBLE)
785         {
786                 gdouble val;
787                 val = ghb_value_double(gval);
788                 for (ii = 0; ii < opts->count; ii++)
789                 {
790                         if (opts->map[ii].ivalue == val)
791                         {
792                                 break;
793                         }
794                 }
795                 return ii;
796         }
797         else if (G_VALUE_TYPE(gval) == G_TYPE_INT ||
798                          G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN ||
799                          G_VALUE_TYPE(gval) == G_TYPE_INT64)
800         {
801                 gint64 val;
802                 val = ghb_value_int64(gval);
803                 for (ii = 0; ii < opts->count; ii++)
804                 {
805                         if ((gint64)opts->map[ii].ivalue == val)
806                         {
807                                 break;
808                         }
809                 }
810                 return ii;
811         }
812         return opts->count;
813 }
814
815 static const gchar*
816 lookup_generic_string(combo_opts_t *opts, const GValue *gval)
817 {
818         gint ii;
819         const gchar *result = "";
820
821         ii = find_combo_entry(opts, gval);
822         if (ii < opts->count)
823         {
824                 result = opts->map[ii].svalue;
825         }
826         return result;
827 }
828
829 static gint
830 lookup_generic_int(combo_opts_t *opts, const GValue *gval)
831 {
832         gint ii;
833         gint result = -1;
834
835         ii = find_combo_entry(opts, gval);
836         if (ii < opts->count)
837         {
838                 result = opts->map[ii].ivalue;
839         }
840         return result;
841 }
842
843 static gdouble
844 lookup_generic_double(combo_opts_t *opts, const GValue *gval)
845 {
846         gint ii;
847         gdouble result = -1;
848
849         ii = find_combo_entry(opts, gval);
850         if (ii < opts->count)
851         {
852                 result = opts->map[ii].ivalue;
853         }
854         return result;
855 }
856
857 static const gchar*
858 lookup_generic_option(combo_opts_t *opts, const GValue *gval)
859 {
860         gint ii;
861         const gchar *result = "";
862
863         ii = find_combo_entry(opts, gval);
864         if (ii < opts->count)
865         {
866                 result = opts->map[ii].option;
867         }
868         return result;
869 }
870
871 static gint
872 lookup_mix_int(const GValue *mix)
873 {
874         gint ii;
875         gint result = 0;
876
877
878         if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
879         {
880                 gchar * str = ghb_value_string(mix);
881                 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
882                 {
883                         if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
884                         {
885                                 result = hb_audio_mixdowns[ii].amixdown;
886                                 break;
887                         }
888                 }
889                 g_free(str);
890         }
891         else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
892                          G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
893                          G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
894         {
895                 gint val = ghb_value_int(mix);
896                 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
897                 {
898                         if (hb_audio_mixdowns[ii].amixdown == val)
899                         {
900                                 result = hb_audio_mixdowns[ii].amixdown;
901                                 break;
902                         }
903                 }
904         }
905         return result;
906 }
907
908 static const gchar*
909 lookup_mix_option(const GValue *mix)
910 {
911         gint ii;
912         gchar *result = "None";
913
914
915         if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
916         {
917                 gchar *str = ghb_value_string(mix);
918                 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
919                 {
920                         if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
921                         {
922                                 result = hb_audio_mixdowns[ii].human_readable_name;
923                                 break;
924                         }
925                 }
926                 g_free(str);
927         }
928         else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
929                          G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
930                          G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
931         {
932                 gint val = ghb_value_int(mix);
933                 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
934                 {
935                         if (hb_audio_mixdowns[ii].amixdown == val)
936                         {
937                                 result = hb_audio_mixdowns[ii].human_readable_name;
938                                 break;
939                         }
940                 }
941         }
942         return result;
943 }
944
945 static const gchar*
946 lookup_mix_string(const GValue *mix)
947 {
948         gint ii;
949         gchar *result = "None";
950
951
952         if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
953         {
954                 gchar *str = ghb_value_string(mix);
955                 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
956                 {
957                         if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
958                         {
959                                 result = hb_audio_mixdowns[ii].short_name;
960                                 break;
961                         }
962                 }
963                 g_free(str);
964         }
965         else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
966                          G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
967                          G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
968         {
969                 gint val = ghb_value_int(mix);
970                 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
971                 {
972                         if (hb_audio_mixdowns[ii].amixdown == val)
973                         {
974                                 result = hb_audio_mixdowns[ii].short_name;
975                                 break;
976                         }
977                 }
978         }
979         return result;
980 }
981
982 static gint
983 lookup_video_rate_int(const GValue *vrate)
984 {
985         gint ii;
986         gchar *str;
987         gint result = 0;
988
989         str = ghb_value_string(vrate);
990         for (ii = 0; ii < hb_video_rates_count; ii++)
991         {
992                 if (strcmp(hb_video_rates[ii].string, str) == 0)
993                 {
994                         result = hb_video_rates[ii].rate;
995                         break;
996                 }
997         }
998         g_free(str);
999         // Default to "same as source"
1000         return result;
1001 }
1002
1003 static const gchar*
1004 lookup_video_rate_option(const GValue *vrate)
1005 {
1006         gint ii;
1007         gchar *str;
1008         const gchar *result = "Same as source";
1009
1010         str = ghb_value_string(vrate);
1011         for (ii = 0; ii < hb_video_rates_count; ii++)
1012         {
1013                 if (strcmp(hb_video_rates[ii].string, str) == 0)
1014                 {
1015                         result = hb_video_rates[ii].string;
1016                         break;
1017                 }
1018         }
1019         g_free(str);
1020         // Default to "same as source"
1021         return result;
1022 }
1023
1024 static gint
1025 lookup_audio_rate_int(const GValue *rate)
1026 {
1027         gint ii;
1028         gint result = 0;
1029
1030         if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
1031         {
1032                 // Coincidentally, the string "source" will return 0
1033                 // which is our flag to use "same as source"
1034                 gchar * str = ghb_value_string(rate);
1035                 for (ii = 0; ii < hb_audio_rates_count; ii++)
1036                 {
1037                         if (strcmp(hb_audio_rates[ii].string, str) == 0)
1038                         {
1039                                 result = hb_audio_rates[ii].rate;
1040                                 break;
1041                         }
1042                 }
1043                 g_free(str);
1044         }
1045         else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
1046                          G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
1047                          G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
1048         {
1049                 for (ii = 0; ii < hb_audio_rates_count; ii++)
1050                 {
1051                         gint val = ghb_value_int(rate);
1052                         if (val == hb_audio_rates[ii].rate)
1053                         {
1054                                 result = hb_audio_rates[ii].rate;
1055                                 break;
1056                         }
1057                 }
1058         }
1059         return result;
1060 }
1061
1062 static const gchar*
1063 lookup_audio_rate_option(const GValue *rate)
1064 {
1065         gint ii;
1066         const gchar *result = "Same as source";
1067
1068         if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
1069         {
1070                 // Coincidentally, the string "source" will return 0
1071                 // which is our flag to use "same as source"
1072                 gchar *str = ghb_value_string(rate);
1073                 for (ii = 0; ii < hb_audio_rates_count; ii++)
1074                 {
1075                         if (strcmp(hb_audio_rates[ii].string, str) == 0)
1076                         {
1077                                 result = hb_audio_rates[ii].string;
1078                                 break;
1079                         }
1080                 }
1081                 g_free(str);
1082         }
1083         else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
1084                          G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
1085                          G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
1086         {
1087                 for (ii = 0; ii < hb_audio_rates_count; ii++)
1088                 {
1089                         gint val = ghb_value_int(rate);
1090                         if (val == hb_audio_rates[ii].rate)
1091                         {
1092                                 result = hb_audio_rates[ii].string;
1093                                 break;
1094                         }
1095                 }
1096         }
1097         return result;
1098 }
1099
1100 gint
1101 ghb_find_closest_audio_rate(gint rate)
1102 {
1103         gint ii;
1104         gint result;
1105
1106         result = 0;
1107         for (ii = 0; ii < hb_audio_rates_count; ii++)
1108         {
1109                 if (rate <= hb_audio_rates[ii].rate)
1110                 {
1111                         result = hb_audio_rates[ii].rate;
1112                         break;
1113                 }
1114         }
1115         return result;
1116 }
1117
1118 hb_rate_t *ghb_audio_bitrates;
1119 int ghb_audio_bitrates_count;
1120
1121 static gint
1122 lookup_audio_bitrate_int(const GValue *rate)
1123 {
1124         gint ii;
1125         gint result = 0;
1126
1127         if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
1128         {
1129                 // Coincidentally, the string "source" will return 0
1130                 // which is our flag to use "same as source"
1131                 gchar *str = ghb_value_string(rate);
1132                 for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
1133                 {
1134                         if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
1135                         {
1136                                 result = ghb_audio_bitrates[ii].rate;
1137                                 break;
1138                         }
1139                 }
1140                 g_free(str);
1141         }
1142         else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
1143                          G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
1144                          G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
1145         {
1146                 gint val = ghb_value_int(rate);
1147                 for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
1148                 {
1149                         if (ghb_audio_bitrates[ii].rate == val)
1150                         {
1151                                 result = ghb_audio_bitrates[ii].rate;
1152                                 break;
1153                         }
1154                 }
1155         }
1156         return result;
1157 }
1158
1159 static const gchar*
1160 lookup_audio_bitrate_option(const GValue *rate)
1161 {
1162         gint ii;
1163         const gchar *result = "Same as source";
1164
1165         if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
1166         {
1167                 // Coincidentally, the string "source" will return 0
1168                 // which is our flag to use "same as source"
1169                 gchar *str = ghb_value_string(rate);
1170                 for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
1171                 {
1172                         if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
1173                         {
1174                                 result = ghb_audio_bitrates[ii].string;
1175                                 break;
1176                         }
1177                 }
1178                 g_free(str);
1179         }
1180         else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
1181                          G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
1182                          G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
1183         {
1184                 gint val = ghb_value_int(rate);
1185                 for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
1186                 {
1187                         if (ghb_audio_bitrates[ii].rate == val)
1188                         {
1189                                 result = ghb_audio_bitrates[ii].string;
1190                                 break;
1191                         }
1192                 }
1193         }
1194         return result;
1195 }
1196
1197 static gint
1198 lookup_audio_lang_int(const GValue *rate)
1199 {
1200         gint ii;
1201         gchar *str;
1202         gint result = 0;
1203
1204         // Coincidentally, the string "source" will return 0
1205         // which is our flag to use "same as source"
1206         str = ghb_value_string(rate);
1207         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1208         {
1209                 if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
1210                 {
1211                         result = ii;
1212                         break;
1213                 }
1214         }
1215         g_free(str);
1216         return result;
1217 }
1218
1219 static const gchar*
1220 lookup_audio_lang_option(const GValue *rate)
1221 {
1222         gint ii;
1223         gchar *str;
1224         const gchar *result = "Same as source";
1225
1226         // Coincidentally, the string "source" will return 0
1227         // which is our flag to use "same as source"
1228         str = ghb_value_string(rate);
1229         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1230         {
1231                 if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
1232                 {
1233                         if (ghb_language_table[ii].native_name[0] != 0)
1234                                 result = ghb_language_table[ii].native_name;
1235                         else
1236                                 result = ghb_language_table[ii].eng_name;
1237                         break;
1238                 }
1239         }
1240         g_free(str);
1241         return result;
1242 }
1243
1244 GValue*
1245 ghb_lookup_acodec_value(gint val)
1246 {
1247         GValue *value = NULL;
1248         gint ii;
1249
1250         for (ii = 0; ii < acodec_opts.count; ii++)
1251         {
1252                 if ((int)acodec_opts.map[ii].ivalue == val)
1253                 {
1254                         value = ghb_string_value_new(acodec_opts.map[ii].shortOpt);
1255                         return value;
1256                 }
1257         }
1258         value = ghb_string_value_new("auto");
1259         return value;
1260 }
1261
1262 static GValue*
1263 get_amix_value(gint val)
1264 {
1265         GValue *value = NULL;
1266         gint ii;
1267
1268         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
1269         {
1270                 if (hb_audio_mixdowns[ii].amixdown == val)
1271                 {
1272                         value = ghb_string_value_new(hb_audio_mixdowns[ii].short_name);
1273                         break;
1274                 }
1275         }
1276         return value;
1277 }
1278
1279 // Handle for libhb.  Gets set by ghb_backend_init()
1280 static hb_handle_t * h_scan = NULL;
1281 static hb_handle_t * h_queue = NULL;
1282
1283 extern void hb_get_temporary_directory(char path[512]);
1284
1285 gchar*
1286 ghb_get_tmp_dir()
1287 {
1288         char dir[512];
1289
1290         hb_get_temporary_directory(dir);
1291         return g_strdup(dir);
1292 }
1293
1294 void
1295 ghb_hb_cleanup(gboolean partial)
1296 {
1297         char dir[512];
1298
1299         hb_get_temporary_directory(dir);
1300         del_tree(dir, !partial);
1301 }
1302
1303 gint
1304 ghb_subtitle_track_source(signal_user_data_t *ud, gint track)
1305 {
1306         gint titleindex;
1307
1308         if (track == -2)
1309                 return SRTSUB;
1310         if (track < 0)
1311                 return VOBSUB;
1312         titleindex = ghb_settings_combo_int(ud->settings, "title");
1313         if (titleindex < 0)
1314                 return VOBSUB;
1315
1316         hb_list_t  * list;
1317         hb_title_t * title;
1318         hb_subtitle_t * sub;
1319         
1320         if (h_scan == NULL) return VOBSUB;
1321         list = hb_get_titles( h_scan );
1322         if( !hb_list_count( list ) )
1323         {
1324                 /* No valid title, stop right there */
1325                 return VOBSUB;
1326         }
1327         title = hb_list_item( list, titleindex );
1328         if (title == NULL) return VOBSUB;       // Bad titleindex
1329         sub = hb_list_item( title->list_subtitle, track);
1330         if (sub != NULL)
1331                 return sub->source;
1332         else
1333                 return VOBSUB;
1334 }
1335
1336 const char*
1337 ghb_subtitle_source_name(gint source)
1338 {
1339         const gchar * name = "Unknown";
1340         switch (source)
1341         {
1342                 case VOBSUB:
1343                         name = "VOBSUB";
1344                         break;
1345                 case TX3GSUB:
1346                         name = "TX3G";
1347                         break;
1348                 case UTF8SUB:
1349                         name = "UTF8";
1350                         break;
1351                 case CC708SUB:
1352                 case CC608SUB:
1353                         name = "CC";
1354                         break;
1355                 case SRTSUB:
1356                         name = "SRT";
1357                         break;
1358                 case SSASUB:
1359                         name = "SSA";
1360                         break;
1361                 default:
1362                         break;
1363         }
1364         return name;
1365 }
1366
1367 const char*
1368 ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track)
1369 {
1370         gint titleindex;
1371         const gchar * name = "Unknown";
1372
1373         if (track == -2)
1374         {
1375                 name = "SRT";
1376                 goto done;
1377         }
1378         if (track == -1)
1379         {
1380                 name = "Bitmap";
1381                 goto done;
1382         }
1383
1384         titleindex = ghb_settings_combo_int(ud->settings, "title");
1385         if (titleindex < 0)
1386                 goto done;
1387
1388         hb_list_t  * list;
1389         hb_title_t * title;
1390         hb_subtitle_t * sub;
1391         
1392         if (h_scan == NULL) 
1393                 goto done;
1394         list = hb_get_titles( h_scan );
1395         if( !hb_list_count( list ) )
1396                 goto done;
1397
1398         title = hb_list_item( list, titleindex );
1399         if (title == NULL)
1400                 goto done;
1401
1402         sub = hb_list_item( title->list_subtitle, track);
1403         if (sub != NULL)
1404         {
1405                 name = ghb_subtitle_source_name(sub->source);
1406         }
1407
1408 done:
1409         return name;
1410 }
1411
1412 gchar*
1413 ghb_subtitle_track_lang(signal_user_data_t *ud, gint track)
1414 {
1415         gint titleindex;
1416
1417         titleindex = ghb_settings_combo_int(ud->settings, "title");
1418         if (titleindex < 0)
1419                 goto fail;
1420         if (track == -1)
1421                 return ghb_get_user_audio_lang(ud, titleindex, 0);
1422         if (track < 0)
1423                 goto fail;
1424
1425         hb_list_t  * list;
1426         hb_title_t * title;
1427         hb_subtitle_t * sub;
1428         
1429         if (h_scan == NULL)
1430                 goto fail;
1431
1432         list = hb_get_titles( h_scan );
1433         if( !hb_list_count( list ) )
1434         {
1435                 /* No valid title, stop right there */
1436                 goto fail;
1437         }
1438         title = hb_list_item( list, titleindex );
1439         if (title == NULL)      // Bad titleindex
1440                 goto fail;
1441         sub = hb_list_item( title->list_subtitle, track);
1442         if (sub != NULL)
1443                 return g_strdup(sub->iso639_2);
1444
1445 fail:
1446         return g_strdup("und");
1447 }
1448
1449 gint
1450 ghb_get_title_number(gint titleindex)
1451 {
1452         hb_list_t  * list;
1453         hb_title_t * title;
1454         
1455         if (h_scan == NULL) return 1;
1456         list = hb_get_titles( h_scan );
1457         if( !hb_list_count( list ) )
1458         {
1459                 /* No valid title, stop right there */
1460                 return 1;
1461         }
1462         title = hb_list_item( list, titleindex );
1463         if (title == NULL) return 1;    // Bad titleindex
1464         return title->index;
1465 }
1466
1467 static hb_audio_config_t*
1468 get_hb_audio(hb_handle_t *h, gint titleindex, gint track)
1469 {
1470         hb_list_t  * list;
1471         hb_title_t * title;
1472     hb_audio_config_t *audio = NULL;
1473         
1474     if (h == NULL) return NULL;
1475         list = hb_get_titles( h );
1476         if( !hb_list_count( list ) )
1477         {
1478                 /* No valid title, stop right there */
1479                 return NULL;
1480         }
1481     title = hb_list_item( list, titleindex );
1482         if (title == NULL) return NULL; // Bad titleindex
1483         if (!hb_list_count(title->list_audio))
1484         {
1485                 return NULL;
1486         }
1487     audio = (hb_audio_config_t *)hb_list_audio_config_item(title->list_audio, track);
1488         return audio;
1489 }
1490
1491 static gint
1492 search_rates(hb_rate_t *rates, gint rate, gint count)
1493 {
1494         gint ii;
1495         for (ii = 0; ii < count; ii++)
1496         {
1497                 if (rates[ii].rate == rate)
1498                         return ii;
1499         }
1500         return -1;
1501 }
1502
1503 static gboolean find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter);
1504
1505 static GtkListStore*
1506 get_combo_box_store(GtkBuilder *builder, const gchar *name)
1507 {
1508         GtkComboBox *combo;
1509         GtkListStore *store;
1510
1511         g_debug("get_combo_box_store() %s\n", name);
1512         // First modify the combobox model to allow greying out of options
1513         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
1514         store = GTK_LIST_STORE(gtk_combo_box_get_model (combo));
1515         return store;
1516 }
1517
1518 static void
1519 grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean grey)
1520 {
1521         GtkListStore *store;
1522         GtkTreeIter iter;
1523         
1524         store = get_combo_box_store(builder, name);
1525         if (find_combo_item_by_int(GTK_TREE_MODEL(store), value, &iter))
1526         {
1527                 gtk_list_store_set(store, &iter, 
1528                                                    1, !grey, 
1529                                                    -1);
1530         }
1531 }
1532
1533 void
1534 ghb_grey_combo_options(GtkBuilder *builder)
1535 {
1536         GtkWidget *widget;
1537         gint container, track, titleindex, acodec;
1538     hb_audio_config_t *aconfig = NULL;
1539         GValue *gval;
1540         
1541         widget = GHB_WIDGET (builder, "title");
1542         gval = ghb_widget_value(widget);
1543         titleindex = ghb_lookup_combo_int("title", gval);
1544         ghb_value_free(gval);
1545         widget = GHB_WIDGET (builder, "AudioTrack");
1546         gval = ghb_widget_value(widget);
1547         track = ghb_lookup_combo_int("AudioTrack", gval);
1548         ghb_value_free(gval);
1549         aconfig = get_hb_audio(h_scan, titleindex, track);
1550         widget = GHB_WIDGET (builder, "FileFormat");
1551         gval = ghb_widget_value(widget);
1552         container = ghb_lookup_combo_int("FileFormat", gval);
1553         ghb_value_free(gval);
1554
1555         grey_combo_box_item(builder, "x264_analyse", 4, TRUE);
1556         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_FAAC, FALSE);
1557         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_LAME, FALSE);
1558         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, FALSE);
1559
1560         gboolean allow_dca = TRUE;
1561         allow_dca = (container != HB_MUX_MP4);
1562
1563         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, FALSE);
1564         if (allow_dca)
1565                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, FALSE);
1566         else
1567                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE);
1568
1569         if (aconfig && aconfig->in.codec != HB_ACODEC_AC3)
1570         {
1571                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, TRUE);
1572         }
1573         if (aconfig && aconfig->in.codec != HB_ACODEC_DCA)
1574         {
1575                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE);
1576         }
1577         grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, FALSE);
1578
1579         widget = GHB_WIDGET (builder, "AudioEncoder");
1580         gval = ghb_widget_value(widget);
1581         acodec = ghb_lookup_combo_int("AudioEncoder", gval);
1582         ghb_value_free(gval);
1583         grey_combo_box_item(builder, "AudioMixdown", 0, TRUE);
1584         if (container == HB_MUX_MP4)
1585         {
1586                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, TRUE);
1587                 grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, TRUE);
1588         }
1589
1590         gboolean allow_mono = TRUE;
1591         gboolean allow_stereo = TRUE;
1592         gboolean allow_dolby = TRUE;
1593         gboolean allow_dpl2 = TRUE;
1594         gboolean allow_6ch = TRUE;
1595         allow_mono = TRUE;
1596         allow_6ch = acodec & ~HB_ACODEC_LAME;
1597         if (aconfig)
1598         {
1599                 gint best = hb_get_best_mixdown(acodec, aconfig->in.channel_layout, 0);
1600
1601                 allow_stereo = best >= HB_AMIXDOWN_STEREO;
1602                 allow_dolby = best >= HB_AMIXDOWN_DOLBY;
1603                 allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
1604                 allow_6ch = best >= HB_AMIXDOWN_6CH;
1605         }
1606         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_MONO, !allow_mono);
1607         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_STEREO, !allow_stereo);
1608         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_DOLBY, !allow_dolby);
1609         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_DOLBYPLII, !allow_dpl2);
1610         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_6CH, !allow_6ch);
1611 }
1612
1613 gint
1614 ghb_get_best_mix(hb_audio_config_t *aconfig, gint acodec, gint mix)
1615 {
1616         int layout;
1617         layout = aconfig ? aconfig->in.channel_layout : 
1618                                                 HB_INPUT_CH_LAYOUT_3F2R | HB_INPUT_CH_LAYOUT_HAS_LFE;
1619         return hb_get_best_mixdown( acodec, layout, mix );
1620 }
1621
1622 // Set up the model for the combo box
1623 static void
1624 init_combo_box(GtkBuilder *builder, const gchar *name)
1625 {
1626         GtkComboBox *combo;
1627         GtkListStore *store;
1628         GtkCellRenderer *cell;
1629
1630         g_debug("init_combo_box() %s\n", name);
1631         // First modify the combobox model to allow greying out of options
1632         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
1633         if (combo == NULL)
1634                 return;
1635         // Store contains:
1636         // 1 - String to display
1637         // 2 - bool indicating whether the entry is selectable (grey or not)
1638         // 3 - String that is used for presets
1639         // 4 - Int value determined by backend
1640         // 5 - String value determined by backend
1641         store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_BOOLEAN, 
1642                                                            G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_STRING);
1643         gtk_combo_box_set_model(combo, GTK_TREE_MODEL(store));
1644
1645         if (GTK_WIDGET_TYPE(combo) == GTK_TYPE_COMBO_BOX)
1646         {
1647                 gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo));
1648         cell = GTK_CELL_RENDERER(gtk_cell_renderer_text_new());
1649         gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
1650         gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell,
1651                 "markup", 0, "sensitive", 1, NULL);
1652         }
1653         else
1654         { // Combo box entry
1655                 gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(combo), 0);
1656         }
1657 }       
1658
1659 static void
1660 audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
1661 {
1662         GtkTreeIter iter;
1663         GtkListStore *store;
1664         gint ii;
1665         gchar *str;
1666         
1667         g_debug("audio_samplerate_opts_set ()\n");
1668         store = get_combo_box_store(builder, name);
1669         gtk_list_store_clear(store);
1670         // Add an item for "Same As Source"
1671         gtk_list_store_append(store, &iter);
1672         gtk_list_store_set(store, &iter, 
1673                                            0, "<small>Same as source</small>", 
1674                                            1, TRUE, 
1675                                            2, "source", 
1676                                            3, 0.0, 
1677                                            4, "source", 
1678                                            -1);
1679         for (ii = 0; ii < count; ii++)
1680         {
1681                 gtk_list_store_append(store, &iter);
1682                 str = g_strdup_printf("<small>%s</small>", rates[ii].string);
1683                 gtk_list_store_set(store, &iter, 
1684                                                    0, str,
1685                                                    1, TRUE, 
1686                                                    2, rates[ii].string, 
1687                                                    3, (gdouble)rates[ii].rate, 
1688                                                    4, rates[ii].string, 
1689                                                    -1);
1690                 g_free(str);
1691         }
1692 }
1693
1694 static void
1695 video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
1696 {
1697         GtkTreeIter iter;
1698         GtkListStore *store;
1699         gint ii;
1700         
1701         g_debug("video_rate_opts_set ()\n");
1702         store = get_combo_box_store(builder, name);
1703         gtk_list_store_clear(store);
1704         // Add an item for "Same As Source"
1705         gtk_list_store_append(store, &iter);
1706         gtk_list_store_set(store, &iter, 
1707                                            0, "Same as source", 
1708                                            1, TRUE, 
1709                                            2, "source", 
1710                                            3, 0.0, 
1711                                            4, "source", 
1712                                            -1);
1713         for (ii = 0; ii < count; ii++)
1714         {
1715                 gchar *desc = "";
1716                 gchar *option;
1717                 if (strcmp(rates[ii].string, "23.976") == 0)
1718                 {
1719                         desc = "(NTSC Film)";
1720                 }
1721                 else if (strcmp(rates[ii].string, "25") == 0)
1722                 {
1723                         desc = "(PAL Film/Video)";
1724                 }
1725                 else if (strcmp(rates[ii].string, "29.97") == 0)
1726                 {
1727                         desc = "(NTSC Video)";
1728                 }
1729                 option = g_strdup_printf ("%s %s", rates[ii].string, desc);
1730                 gtk_list_store_append(store, &iter);
1731                 gtk_list_store_set(store, &iter, 
1732                                                    0, option, 
1733                                                    1, TRUE, 
1734                                                    2, rates[ii].string, 
1735                                                    3, (gdouble)rates[ii].rate, 
1736                                                    4, rates[ii].string, 
1737                                                    -1);
1738                 g_free(option);
1739         }
1740 }
1741
1742 static void
1743 mix_opts_set(GtkBuilder *builder, const gchar *name)
1744 {
1745         GtkTreeIter iter;
1746         GtkListStore *store;
1747         gint ii;
1748         gchar *str;
1749         
1750         g_debug("mix_opts_set ()\n");
1751         store = get_combo_box_store(builder, name);
1752         gtk_list_store_clear(store);
1753         gtk_list_store_append(store, &iter);
1754         gtk_list_store_set(store, &iter, 
1755                                            0, "<small>None</small>", 
1756                                            1, TRUE, 
1757                                            2, "none", 
1758                                            3, 0.0, 
1759                                            4, "none", 
1760                                            -1);
1761         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
1762         {
1763                 gtk_list_store_append(store, &iter);
1764                 str = g_strdup_printf("<small>%s</small>",
1765                         hb_audio_mixdowns[ii].human_readable_name);
1766                 gtk_list_store_set(store, &iter, 
1767                                                    0, str,
1768                                                    1, TRUE, 
1769                                                    2, hb_audio_mixdowns[ii].short_name, 
1770                                                    3, (gdouble)hb_audio_mixdowns[ii].amixdown, 
1771                                                    4, hb_audio_mixdowns[ii].internal_name, 
1772                                                    -1);
1773                 g_free(str);
1774         }
1775 }
1776
1777 static void
1778 srt_codeset_opts_set(GtkBuilder *builder, const gchar *name)
1779 {
1780         GtkTreeIter iter;
1781         GtkListStore *store;
1782         gint ii;
1783         
1784         g_debug("srt_codeset_opts_set ()\n");
1785         store = get_combo_box_store(builder, name);
1786         gtk_list_store_clear(store);
1787         for (ii = 0; ii < SRT_TABLE_SIZE; ii++)
1788         {
1789                 gtk_list_store_append(store, &iter);
1790                 gtk_list_store_set(store, &iter, 
1791                                                    0, srt_codeset_table[ii],
1792                                                    1, TRUE, 
1793                                                    2, srt_codeset_table[ii],
1794                                                    3, (gdouble)ii, 
1795                                                    4, srt_codeset_table[ii],
1796                                                    -1);
1797         }
1798         GtkComboBoxEntry *cbe;
1799
1800         cbe = GTK_COMBO_BOX_ENTRY(GHB_WIDGET(builder, name));
1801         //gtk_combo_box_entry_set_text_column(cbe, 0);
1802 }
1803
1804 static void
1805 language_opts_set(GtkBuilder *builder, const gchar *name)
1806 {
1807         GtkTreeIter iter;
1808         GtkListStore *store;
1809         gint ii;
1810         
1811         g_debug("language_opts_set ()\n");
1812         store = get_combo_box_store(builder, name);
1813         gtk_list_store_clear(store);
1814         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1815         {
1816                 const gchar *lang;
1817
1818                 if (ghb_language_table[ii].native_name[0] != 0)
1819                         lang = ghb_language_table[ii].native_name;
1820                 else
1821                         lang = ghb_language_table[ii].eng_name;
1822                 
1823                 gtk_list_store_append(store, &iter);
1824                 gtk_list_store_set(store, &iter, 
1825                                                    0, lang,
1826                                                    1, TRUE, 
1827                                                    2, ghb_language_table[ii].iso639_2, 
1828                                                    3, (gdouble)ii, 
1829                                                    4, ghb_language_table[ii].iso639_1, 
1830                                                    -1);
1831         }
1832 }
1833
1834 static gchar **titles = NULL;
1835
1836 void
1837 title_opts_set(GtkBuilder *builder, const gchar *name)
1838 {
1839         GtkTreeIter iter;
1840         GtkListStore *store;
1841         hb_list_t  * list = NULL;
1842         hb_title_t * title = NULL;
1843         gint ii;
1844         gint count = 0;
1845         
1846         g_debug("title_opts_set ()\n");
1847         store = get_combo_box_store(builder, name);
1848         gtk_list_store_clear(store);
1849         if (h_scan != NULL)
1850         {
1851                 list = hb_get_titles( h_scan );
1852                 count = hb_list_count( list );
1853                 if (count > 100) count = 100;
1854         }
1855         if (titles) g_strfreev(titles);
1856         if (title_opts.map) g_free(title_opts.map);
1857         if (count > 0)
1858         {
1859                 title_opts.count = count;
1860                 title_opts.map = g_malloc(count*sizeof(options_map_t));
1861                 titles = g_malloc((count+1) * sizeof(gchar*));
1862         }
1863         else
1864         {
1865                 title_opts.count = 1;
1866                 title_opts.map = g_malloc(sizeof(options_map_t));
1867                 titles = NULL;
1868         }
1869         if( count <= 0 )
1870         {
1871                 // No titles.  Fill in a default.
1872                 gtk_list_store_append(store, &iter);
1873                 gtk_list_store_set(store, &iter, 
1874                                                    0, "No Titles", 
1875                                                    1, TRUE, 
1876                                                    2, "none", 
1877                                                    3, -1.0, 
1878                                                    4, "none", 
1879                                                    -1);
1880                 title_opts.map[0].option = "No Titles";
1881                 title_opts.map[0].shortOpt = "none";
1882                 title_opts.map[0].ivalue = -1;
1883                 title_opts.map[0].svalue = "none";
1884                 return;
1885         }
1886         for (ii = 0; ii < count; ii++)
1887         {
1888                 title = (hb_title_t*)hb_list_item(list, ii);
1889                 if (title->type == HB_STREAM_TYPE)
1890                 {
1891                         if (title->duration != 0)
1892                         {
1893                 char *tmp;
1894                                 tmp  = g_strdup_printf ("%d - %02dh%02dm%02ds - %s",
1895                                         title->index, title->hours, title->minutes, title->seconds, 
1896                                         title->name);
1897                 titles[ii] = g_markup_escape_text(tmp, -1);
1898                 g_free(tmp);
1899                         }
1900                         else
1901                         {
1902                 char *tmp;
1903                                 tmp  = g_strdup_printf ("%d - %s", 
1904                                                                                 title->index, title->name);
1905                 titles[ii] = g_markup_escape_text(tmp, -1);
1906                 g_free(tmp);
1907                         }
1908                 }
1909                 else
1910                 {
1911                         if (title->duration != 0)
1912                         {
1913                                 titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds",
1914                                         title->index, title->hours, title->minutes, title->seconds);
1915                         }
1916                         else
1917                         {
1918                                 titles[ii]  = g_strdup_printf ("%d - Unknown Length", 
1919                                                                                 title->index);
1920                         }
1921                 }
1922                 gtk_list_store_append(store, &iter);
1923                 gtk_list_store_set(store, &iter, 
1924                                                    0, titles[ii], 
1925                                                    1, TRUE, 
1926                                                    2, titles[ii], 
1927                                                    3, (gdouble)ii, 
1928                                                    4, titles[ii], 
1929                                                    -1);
1930                 title_opts.map[ii].option = titles[ii];
1931                 title_opts.map[ii].shortOpt = titles[ii];
1932                 title_opts.map[ii].ivalue = ii;
1933                 title_opts.map[ii].svalue = titles[ii];
1934         }
1935         titles[ii] = NULL;
1936 }
1937
1938 static gboolean
1939 find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter)
1940 {
1941         gdouble ivalue;
1942         gboolean foundit = FALSE;
1943         
1944         if (gtk_tree_model_get_iter_first (store, iter))
1945         {
1946                 do
1947                 {
1948                         gtk_tree_model_get(store, iter, 3, &ivalue, -1);
1949                         if (value == (gint)ivalue)
1950                         {
1951                                 foundit = TRUE;
1952                                 break;
1953                         }
1954                 } while (gtk_tree_model_iter_next (store, iter));
1955         }
1956         return foundit;
1957 }
1958
1959 void
1960 audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1961 {
1962         GtkTreeIter iter;
1963         GtkListStore *store;
1964         hb_list_t  * list = NULL;
1965         hb_title_t * title = NULL;
1966     hb_audio_config_t * audio;
1967         gint ii;
1968         gint count = 0;
1969         gchar *str;
1970         
1971         g_debug("audio_track_opts_set ()\n");
1972         store = get_combo_box_store(builder, name);
1973         gtk_list_store_clear(store);
1974         if (h_scan != NULL)
1975         {
1976                 list = hb_get_titles( h_scan );
1977             title = (hb_title_t*)hb_list_item( list, titleindex );
1978                 if (title != NULL)
1979                 {
1980                         count = hb_list_count( title->list_audio );
1981                 }
1982         }
1983         if (count > 100) count = 100;
1984         if (audio_track_opts.map) g_free(audio_track_opts.map);
1985         if (count > 0)
1986         {
1987                 audio_track_opts.count = count;
1988                 audio_track_opts.map = g_malloc(count*sizeof(options_map_t));
1989         }
1990         else
1991         {
1992                 audio_track_opts.count = 1;
1993                 audio_track_opts.map = g_malloc(sizeof(options_map_t));
1994         }
1995         if( count <= 0 )
1996         {
1997                 // No audio. set some default
1998                 gtk_list_store_append(store, &iter);
1999                 gtk_list_store_set(store, &iter, 
2000                                                    0, "<small>No Audio</small>", 
2001                                                    1, TRUE, 
2002                                                    2, "none", 
2003                                                    3, -1.0, 
2004                                                    4, "none", 
2005                                                    -1);
2006                 audio_track_opts.map[0].option = "No Audio";
2007                 audio_track_opts.map[0].shortOpt = "none";
2008                 audio_track_opts.map[0].ivalue = -1;
2009                 audio_track_opts.map[0].svalue = "none";
2010                 return;
2011         }
2012         index_str_init(count-1);
2013         for (ii = 0; ii < count; ii++)
2014         {
2015         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, ii );
2016                 gtk_list_store_append(store, &iter);
2017                 str = g_strdup_printf("<small>%s</small>", audio->lang.description);
2018                 gtk_list_store_set(store, &iter, 
2019                                                    0, str,
2020                                                    1, TRUE, 
2021                                                    2, index_str[ii], 
2022                                                    3, (gdouble)ii, 
2023                                                    4, index_str[ii], 
2024                                                    -1);
2025                 g_free(str);
2026                 audio_track_opts.map[ii].option = audio->lang.description,
2027                 audio_track_opts.map[ii].shortOpt = index_str[ii];
2028                 audio_track_opts.map[ii].ivalue = ii;
2029                 audio_track_opts.map[ii].svalue = index_str[ii];
2030         }
2031 }
2032
2033 void
2034 subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
2035 {
2036         GtkTreeIter iter;
2037         GtkListStore *store;
2038         hb_list_t  * list = NULL;
2039         hb_title_t * title = NULL;
2040         hb_subtitle_t * subtitle;
2041         gint ii, count = 0;
2042         static char ** options = NULL;
2043         
2044         g_debug("subtitle_track_opts_set ()\n");
2045         store = get_combo_box_store(builder, name);
2046         gtk_list_store_clear(store);
2047         if (h_scan != NULL)
2048         {
2049                 list = hb_get_titles( h_scan );
2050             title = (hb_title_t*)hb_list_item( list, titleindex );
2051                 if (title != NULL)
2052                 {
2053                         count = hb_list_count( title->list_subtitle );
2054                 }
2055         }
2056         if (count > 100) count = 100;
2057         if (subtitle_opts.map) g_free(subtitle_opts.map);
2058         if (count > 0)
2059         {
2060                 subtitle_opts.count = count+1;
2061                 subtitle_opts.map = g_malloc((count+1)*sizeof(options_map_t));
2062         }
2063         else
2064         {
2065                 subtitle_opts.count = LANG_TABLE_SIZE+1;
2066                 subtitle_opts.map = g_malloc((LANG_TABLE_SIZE+1)*sizeof(options_map_t));
2067         }
2068         gtk_list_store_append(store, &iter);
2069         gtk_list_store_set(store, &iter, 
2070                                            0, "Foreign Audio Search", 
2071                                            1, TRUE, 
2072                                            2, "-1", 
2073                                            3, -1.0, 
2074                                            4, "auto", 
2075                                            -1);
2076         subtitle_opts.map[0].option = "Foreign Audio Search";
2077         subtitle_opts.map[0].shortOpt = "-1";
2078         subtitle_opts.map[0].ivalue = -1;
2079         subtitle_opts.map[0].svalue = "auto";
2080         if (count > 0)
2081         {
2082                 if (options != NULL)
2083                         g_strfreev(options);
2084                 options = g_malloc((count+1)*sizeof(gchar*));
2085                 index_str_init(count-1);
2086                 for (ii = 0; ii < count; ii++)
2087                 {
2088                 subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
2089                         options[ii] = g_strdup_printf("%d - %s (%s)", ii+1, 
2090                                 subtitle->lang, 
2091                                 ghb_subtitle_source_name(subtitle->source));
2092                         subtitle_opts.map[ii+1].option = options[ii];
2093                         subtitle_opts.map[ii+1].shortOpt = index_str[ii];
2094                         subtitle_opts.map[ii+1].ivalue = ii;
2095                         subtitle_opts.map[ii+1].svalue = subtitle->iso639_2;
2096                         gtk_list_store_append(store, &iter);
2097                         gtk_list_store_set(store, &iter, 
2098                                                 0, options[ii], 
2099                                                 1, TRUE, 
2100                                                 2, index_str[ii], 
2101                                                 3, (gdouble)ii, 
2102                                                 4, subtitle->iso639_2, 
2103                                                 -1);
2104                 }
2105                 options[count] = NULL;
2106         }
2107         else
2108         {
2109                 index_str_init(LANG_TABLE_SIZE-1);
2110                 for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
2111                 {
2112                         const gchar *lang;
2113
2114                         if (ghb_language_table[ii].native_name[0] != 0)
2115                                 lang = ghb_language_table[ii].native_name;
2116                         else
2117                                 lang = ghb_language_table[ii].eng_name;
2118
2119                         subtitle_opts.map[ii+1].option = lang;
2120                         subtitle_opts.map[ii+1].shortOpt = index_str[ii];
2121                         subtitle_opts.map[ii+1].ivalue = ii;
2122                         subtitle_opts.map[ii+1].svalue = ghb_language_table[ii].iso639_2;
2123                         gtk_list_store_append(store, &iter);
2124                         gtk_list_store_set(store, &iter, 
2125                                         0, lang,
2126                                         1, TRUE, 
2127                                         2, index_str[ii],
2128                                         3, (gdouble)ii, 
2129                                         4, ghb_language_table[ii].iso639_2, 
2130                                         -1);
2131                 }
2132         }
2133 }
2134
2135 gint
2136 ghb_longest_title()
2137 {
2138         hb_list_t  * list;
2139         hb_title_t * title;
2140         gint ii;
2141         gint count = 0;
2142         gint titleindex = 0;
2143         gint feature;
2144         
2145         g_debug("ghb_longest_title ()\n");
2146         if (h_scan == NULL) return 0;
2147         list = hb_get_titles( h_scan );
2148         count = hb_list_count( list );
2149         if (count > 100) count = 100;
2150         if (count < 1) return 0;
2151         title = (hb_title_t*)hb_list_item(list, 0);
2152         feature = title->job->feature;
2153         for (ii = 0; ii < count; ii++)
2154         {
2155                 title = (hb_title_t*)hb_list_item(list, ii);
2156                 if (title->index == feature)
2157                 {
2158                         return ii;
2159                 }
2160         }
2161         return titleindex;
2162 }
2163
2164 gchar*
2165 ghb_get_source_audio_lang(gint titleindex, gint track)
2166 {
2167         hb_list_t  * list;
2168         hb_title_t * title;
2169     hb_audio_config_t * audio;
2170         gchar *lang = NULL;
2171         
2172         g_debug("ghb_lookup_1st_audio_lang ()\n");
2173         if (h_scan == NULL) 
2174                 return NULL;
2175         list = hb_get_titles( h_scan );
2176     title = (hb_title_t*)hb_list_item( list, titleindex );
2177         if (title == NULL)
2178                 return NULL;
2179         if (hb_list_count( title->list_audio ) <= track)
2180                 return NULL;
2181
2182         audio = hb_list_audio_config_item(title->list_audio, track);
2183         if (audio == NULL)
2184                 return NULL;
2185
2186         lang = g_strdup(audio->lang.iso639_2);
2187         return lang;
2188 }
2189
2190 static gboolean*
2191 get_track_used(gint acodec, GHashTable *track_indices, gint count)
2192 {
2193         gboolean *used;
2194
2195         used = g_hash_table_lookup(track_indices, &acodec);
2196         if (used == NULL)
2197         {
2198                 gint *key;
2199
2200                 used = g_malloc0(count * sizeof(gboolean));
2201                 key = g_malloc(sizeof(gint));
2202                 *key = acodec;
2203                 g_hash_table_insert(track_indices, key, used);
2204         }
2205         return used;
2206 }
2207
2208 gint
2209 ghb_find_audio_track(
2210         gint titleindex, 
2211         const gchar *lang, 
2212         gint acodec,
2213         gint fallback_acodec,
2214         GHashTable *track_indices)
2215 {
2216         hb_list_t  * list;
2217         hb_title_t * title;
2218         hb_audio_config_t * audio;
2219         gint ii;
2220         gint count = 0;
2221         gint track = -1;
2222         gint max_chan;
2223         gboolean *used = NULL;
2224         gboolean *passthru_used;
2225         gint try_acodec;
2226         gint passthru_acodec;
2227         gboolean passthru;
2228         gint channels;
2229         
2230         g_debug("find_audio_track ()\n");
2231         if (h_scan == NULL) return -1;
2232         list = hb_get_titles( h_scan );
2233         title = (hb_title_t*)hb_list_item( list, titleindex );
2234         if (title != NULL)
2235         {
2236                 count = hb_list_count( title->list_audio );
2237         }
2238         if (count > 10) count = 10;
2239         // Try to find an item that matches the preferred language and
2240         // the passthru codec type
2241         max_chan = 0;
2242         passthru = (acodec & HB_ACODEC_PASS_FLAG) != 0;
2243         if (passthru)
2244         {
2245                 for (ii = 0; ii < count; ii++)
2246                 {
2247                         audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2248                                                                                                         title->list_audio, ii );
2249                         passthru_acodec = HB_ACODEC_PASS_MASK & acodec & audio->in.codec;
2250                         // Is the source track use a passthru capable codec?
2251                         if (passthru_acodec == 0)
2252                                 continue;
2253                         used = get_track_used(passthru_acodec, track_indices, count);
2254                         // Has the track already been used with this codec?
2255                         if (used[ii])
2256                                 continue;
2257
2258                         channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2259                                                                                                         audio->in.channel_layout);
2260                         // Find a track that is not visually impaired or dirctor's
2261                         // commentary, and has the highest channel count.
2262                         if ((audio->lang.type < 2) &&
2263                                 ((strcmp(lang, audio->lang.iso639_2) == 0) ||
2264                                 (strcmp(lang, "und") == 0)))
2265                         {
2266                                 if (channels > max_chan)
2267                                 {
2268                                         track = ii;
2269                                         max_chan = channels;
2270                                 }
2271                         }
2272                 }
2273                 try_acodec = fallback_acodec;
2274         }
2275         else
2276         {
2277                 try_acodec = acodec;
2278         }
2279         if (track > -1)
2280         {
2281                 used[track] = TRUE;
2282                 return track;
2283         }
2284         // Try to find an item that matches the preferred language
2285         max_chan = 0;
2286         used = get_track_used(try_acodec, track_indices, count);
2287         for (ii = 0; ii < count; ii++)
2288         {
2289                 // Has the track already been used with this codec?
2290                 if (used[ii])
2291                         continue;
2292                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2293                                                                                                 title->list_audio, ii );
2294                 passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
2295                 if (passthru_acodec && passthru)
2296                 {
2297                         passthru_used = get_track_used(passthru_acodec, track_indices, count);
2298                         // Has the track already been used with this codec for passthru?
2299                         if (passthru_used[ii])
2300                                 continue;
2301                 }
2302                 channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2303                                                                                                 audio->in.channel_layout);
2304                 // Find a track that is not visually impaired or dirctor's commentary
2305                 if ((audio->lang.type < 2) &&
2306                         ((strcmp(lang, audio->lang.iso639_2) == 0) ||
2307                         (strcmp(lang, "und") == 0)))
2308                 {
2309                         if (channels > max_chan)
2310                         {
2311                                 track = ii;
2312                                 max_chan = channels;
2313                         }
2314                 }
2315         }
2316         if (track > -1)
2317         {
2318                 used[track] = TRUE;
2319                 return track;
2320         }
2321         // Try to fine an item that does not match the preferred language and
2322         // matches the passthru codec type
2323         max_chan = 0;
2324         if (passthru)
2325         {
2326                 for (ii = 0; ii < count; ii++)
2327                 {
2328                         audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2329                                                                                                         title->list_audio, ii );
2330                         passthru_acodec = HB_ACODEC_PASS_MASK & acodec & audio->in.codec;
2331                         // Is the source track use a passthru capable codec?
2332                         if (passthru_acodec == 0)
2333                                 continue;
2334                         used = get_track_used(passthru_acodec, track_indices, count);
2335                         // Has the track already been used with this codec?
2336                         if (used[ii])
2337                                 continue;
2338
2339                         channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2340                                                                                                         audio->in.channel_layout);
2341                         // Find a track that is not visually impaired or dirctor's
2342                         // commentary, and has the highest channel count.
2343                         if (audio->lang.type < 2)
2344                         {
2345                                 if (channels > max_chan)
2346                                 {
2347                                         track = ii;
2348                                         max_chan = channels;
2349                                 }
2350                         }
2351                 }
2352                 try_acodec = fallback_acodec;
2353         }
2354         else
2355         {
2356                 try_acodec = acodec;
2357         }
2358         if (track > -1)
2359         {
2360                 used[track] = TRUE;
2361                 return track;
2362         }
2363         // Try to fine an item that does not match the preferred language
2364         max_chan = 0;
2365         used = get_track_used(try_acodec, track_indices, count);
2366         for (ii = 0; ii < count; ii++)
2367         {
2368                 // Has the track already been used with this codec?
2369                 if (used[ii])
2370                         continue;
2371                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2372                                                                                                         title->list_audio, ii );
2373                 passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
2374                 channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2375                                                                                                 audio->in.channel_layout);
2376                 if (passthru_acodec && passthru)
2377                 {
2378                         passthru_used = get_track_used(passthru_acodec, track_indices, count);
2379                         // Has the track already been used with this codec for passthru?
2380                         if (passthru_used[ii])
2381                                 continue;
2382                 }
2383                 // Find a track that is not visually impaired or dirctor's commentary
2384                 if (audio->lang.type < 2)
2385                 {
2386                         if (channels > max_chan)
2387                         {
2388                                 track = ii;
2389                                 max_chan = channels;
2390                         }
2391                 }
2392         }
2393         if (track > -1)
2394         {
2395                 used[track] = TRUE;
2396                 return track;
2397         }
2398         // Last ditch, anything goes
2399         for (ii = 0; ii < count; ii++)
2400         {
2401                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2402                                                                                                 title->list_audio, ii );
2403                 passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
2404                 if (passthru_acodec && passthru)
2405                 {
2406                         passthru_used = get_track_used(passthru_acodec, track_indices, count);
2407                         // Has the track already been used with this codec for passthru?
2408                         if (passthru_used[ii])
2409                                 continue;
2410                 }
2411                 // Has the track already been used with this codec?
2412                 if (!used[ii])
2413                 {
2414                         track = ii;
2415                         break;
2416                 }
2417         }
2418         if (track > -1)
2419         {
2420                 used[track] = TRUE;
2421         }
2422         return track;
2423 }
2424
2425 gint
2426 ghb_find_pref_subtitle_track(const gchar *lang)
2427 {
2428         gint ii, count;
2429         count = subtitle_opts.count;
2430         for (ii = 0; ii < count; ii++)
2431         {
2432                 if (strcmp(lang, subtitle_opts.map[ii].svalue) == 0)
2433                 {
2434                         return subtitle_opts.map[ii].ivalue;
2435                 }
2436         }
2437         return -2;
2438 }
2439
2440 gint
2441 ghb_find_cc_track(gint titleindex)
2442 {
2443         hb_list_t  * list;
2444         hb_title_t * title;
2445         hb_subtitle_t * subtitle;
2446         gint count, ii;
2447         
2448         g_debug("ghb_find_cc_track ()\n");
2449         if (h_scan == NULL) return -2;
2450         list = hb_get_titles( h_scan );
2451         title = (hb_title_t*)hb_list_item( list, titleindex );
2452         if (title != NULL)
2453         {
2454                 count = hb_list_count( title->list_subtitle );
2455                 // Try to find an item that matches the preferred language
2456                 for (ii = 0; ii < count; ii++)
2457                 {
2458                 subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
2459                         if (subtitle->source == CC608SUB || subtitle->source == CC708SUB)
2460                                 return ii;
2461                 }
2462         }
2463         return -2;
2464 }
2465
2466 static gboolean
2467 canForce(int source)
2468 {
2469         return (source == VOBSUB);
2470 }
2471
2472 static gboolean
2473 canBurn(int source)
2474 {
2475         return (source == VOBSUB || source == SSASUB);
2476 }
2477
2478 gint
2479 ghb_find_subtitle_track(
2480         gint          titleindex, 
2481         const gchar * lang, 
2482         gboolean      burn,
2483         gboolean      force,
2484         gint          source,
2485         GHashTable  * track_indices)
2486 {
2487         hb_list_t  * list;
2488         hb_title_t * title;
2489         hb_subtitle_t * subtitle;
2490         gint count, ii;
2491         gboolean *used;
2492         
2493         g_debug("find_subtitle_track ()\n");
2494         if (strcmp(lang, "auto") == 0)
2495                 return -1;
2496         if (h_scan == NULL) return -1;
2497         list = hb_get_titles( h_scan );
2498         title = (hb_title_t*)hb_list_item( list, titleindex );
2499         if (title != NULL)
2500         {
2501                 count = hb_list_count( title->list_subtitle );
2502                 used = g_hash_table_lookup(track_indices, lang);
2503                 if (used == NULL)
2504                 {
2505                         used = g_malloc0(count * sizeof(gboolean));
2506                         g_hash_table_insert(track_indices, g_strdup(lang), used);
2507                 }
2508                 // Try to find an item that matches the preferred language and source
2509                 for (ii = 0; ii < count; ii++)
2510                 {
2511                         if (used[ii])
2512                                 continue;
2513
2514                 subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
2515                         if (source == subtitle->source &&
2516                                 ((strcmp(lang, subtitle->iso639_2) == 0) ||
2517                                  (strcmp(lang, "und") == 0)))
2518                         {
2519                                 used[ii] = TRUE;
2520                                 return ii;
2521                         }
2522                 }
2523                 // Try to find an item that matches the preferred language
2524                 for (ii = 0; ii < count; ii++)
2525                 {
2526                         if (used[ii])
2527                                 continue;
2528
2529                 subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
2530                         if (((!force || (force && canForce(subtitle->source))) &&
2531                                  (!burn  || (burn  &&  canBurn(subtitle->source)))) &&
2532                                 ((strcmp(lang, subtitle->iso639_2) == 0) ||
2533                                  (strcmp(lang, "und") == 0)))
2534                         {
2535                                 used[ii] = TRUE;
2536                                 return ii;
2537                         }
2538                 }
2539         }
2540         return -2;
2541 }
2542
2543 static void
2544 generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
2545 {
2546         GtkTreeIter iter;
2547         GtkListStore *store;
2548         gint ii;
2549         
2550         g_debug("generic_opts_set ()\n");
2551         if (name == NULL || opts == NULL) return;
2552         store = get_combo_box_store(builder, name);
2553         gtk_list_store_clear(store);
2554         for (ii = 0; ii < opts->count; ii++)
2555         {
2556                 gtk_list_store_append(store, &iter);
2557                 gtk_list_store_set(store, &iter, 
2558                                                    0, opts->map[ii].option, 
2559                                                    1, TRUE, 
2560                                                    2, opts->map[ii].shortOpt, 
2561                                                    3, opts->map[ii].ivalue, 
2562                                                    4, opts->map[ii].svalue, 
2563                                                    -1);
2564         }
2565 }
2566
2567 static void
2568 small_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
2569 {
2570         GtkTreeIter iter;
2571         GtkListStore *store;
2572         gint ii;
2573         gchar *str;
2574         
2575         g_debug("small_opts_set ()\n");
2576         if (name == NULL || opts == NULL) return;
2577         store = get_combo_box_store(builder, name);
2578         gtk_list_store_clear(store);
2579         for (ii = 0; ii < opts->count; ii++)
2580         {
2581                 gtk_list_store_append(store, &iter);
2582                 str = g_strdup_printf("<small>%s</small>", opts->map[ii].option);
2583                 gtk_list_store_set(store, &iter, 
2584                                                    0, str,
2585                                                    1, TRUE, 
2586                                                    2, opts->map[ii].shortOpt, 
2587                                                    3, opts->map[ii].ivalue, 
2588                                                    4, opts->map[ii].svalue, 
2589                                                    -1);
2590                 g_free(str);
2591         }
2592 }
2593
2594 combo_opts_t*
2595 find_combo_table(const gchar *name)
2596 {
2597         gint ii;
2598
2599         for (ii = 0; combo_name_map[ii].name != NULL; ii++)
2600         {
2601                 if (strcmp(name, combo_name_map[ii].name) == 0)
2602                 {
2603                         return combo_name_map[ii].opts;
2604                 }
2605         }
2606         return NULL;
2607 }
2608
2609 gint
2610 ghb_lookup_combo_int(const gchar *name, const GValue *gval)
2611 {
2612         if (gval == NULL)
2613                 return 0;
2614         if (strcmp(name, "AudioBitrate") == 0)
2615                 return lookup_audio_bitrate_int(gval);
2616         else if (strcmp(name, "AudioSamplerate") == 0)
2617                 return lookup_audio_rate_int(gval);
2618         else if (strcmp(name, "VideoFramerate") == 0)
2619                 return lookup_video_rate_int(gval);
2620         else if (strcmp(name, "AudioMixdown") == 0)
2621                 return lookup_mix_int(gval);
2622         else if (strcmp(name, "SrtLanguage") == 0)
2623                 return lookup_audio_lang_int(gval);
2624         else if (strcmp(name, "PreferredLanguage") == 0)
2625                 return lookup_audio_lang_int(gval);
2626         else
2627         {
2628                 return lookup_generic_int(find_combo_table(name), gval);
2629         }
2630         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2631         return 0;
2632 }
2633
2634 gdouble
2635 ghb_lookup_combo_double(const gchar *name, const GValue *gval)
2636 {
2637         if (gval == NULL)
2638                 return 0;
2639         if (strcmp(name, "AudioBitrate") == 0)
2640                 return lookup_audio_bitrate_int(gval);
2641         else if (strcmp(name, "AudioSamplerate") == 0)
2642                 return lookup_audio_rate_int(gval);
2643         else if (strcmp(name, "VideoFramerate") == 0)
2644                 return lookup_video_rate_int(gval);
2645         else if (strcmp(name, "AudioMixdown") == 0)
2646                 return lookup_mix_int(gval);
2647         else if (strcmp(name, "SrtLanguage") == 0)
2648                 return lookup_audio_lang_int(gval);
2649         else if (strcmp(name, "PreferredLanguage") == 0)
2650                 return lookup_audio_lang_int(gval);
2651         else
2652         {
2653                 return lookup_generic_double(find_combo_table(name), gval);
2654         }
2655         g_warning("ghb_lookup_combo_double() couldn't find %s", name);
2656         return 0;
2657 }
2658
2659 const gchar*
2660 ghb_lookup_combo_option(const gchar *name, const GValue *gval)
2661 {
2662         if (gval == NULL)
2663                 return NULL;
2664         if (strcmp(name, "AudioBitrate") == 0)
2665                 return lookup_audio_bitrate_option(gval);
2666         else if (strcmp(name, "AudioSamplerate") == 0)
2667                 return lookup_audio_rate_option(gval);
2668         else if (strcmp(name, "VideoFramerate") == 0)
2669                 return lookup_video_rate_option(gval);
2670         else if (strcmp(name, "AudioMixdown") == 0)
2671                 return lookup_mix_option(gval);
2672         else if (strcmp(name, "SrtLanguage") == 0)
2673                 return lookup_audio_lang_option(gval);
2674         else if (strcmp(name, "PreferredLanguage") == 0)
2675                 return lookup_audio_lang_option(gval);
2676         else
2677         {
2678                 return lookup_generic_option(find_combo_table(name), gval);
2679         }
2680         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2681         return NULL;
2682 }
2683
2684 const gchar*
2685 ghb_lookup_combo_string(const gchar *name, const GValue *gval)
2686 {
2687         if (gval == NULL)
2688                 return NULL;
2689         if (strcmp(name, "AudioBitrate") == 0)
2690                 return lookup_audio_bitrate_option(gval);
2691         else if (strcmp(name, "AudioSamplerate") == 0)
2692                 return lookup_audio_rate_option(gval);
2693         else if (strcmp(name, "VideoFramerate") == 0)
2694                 return lookup_video_rate_option(gval);
2695         else if (strcmp(name, "AudioMixdown") == 0)
2696                 return lookup_mix_string(gval);
2697         else if (strcmp(name, "SrtLanguage") == 0)
2698                 return lookup_audio_lang_option(gval);
2699         else if (strcmp(name, "PreferredLanguage") == 0)
2700                 return lookup_audio_lang_option(gval);
2701         else
2702         {
2703                 return lookup_generic_string(find_combo_table(name), gval);
2704         }
2705         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2706         return NULL;
2707 }
2708
2709 void
2710 ghb_update_ui_combo_box(
2711         signal_user_data_t *ud, 
2712         const gchar *name, 
2713         gint user_data, 
2714         gboolean all)
2715 {
2716         GtkComboBox *combo = NULL;
2717         gint signal_id;
2718         gint handler_id = 0;
2719
2720         if (name != NULL)
2721         {               
2722                 g_debug("ghb_update_ui_combo_box() %s\n", name);
2723                 // Clearing a combo box causes a rash of "changed" events, even when
2724                 // the active item is -1 (inactive).  To control things, I'm disabling
2725                 // the event till things are settled down.
2726                 combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
2727                 signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX);
2728                 if (signal_id > 0)
2729                 {
2730                         // Valid signal id found.  This should always succeed.
2731                         handler_id = g_signal_handler_find ((gpointer)combo, G_SIGNAL_MATCH_ID, 
2732                                                                                                 signal_id, 0, 0, 0, 0);
2733                         if (handler_id > 0)
2734                         {
2735                                 // This should also always succeed
2736                                 g_signal_handler_block ((gpointer)combo, handler_id);
2737                         }
2738                 }
2739         }       
2740         if (all)
2741         {
2742                 audio_bitrate_opts_set(ud->builder, "AudioBitrate");
2743                 audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
2744                 video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
2745                 mix_opts_set(ud->builder, "AudioMixdown");
2746                 language_opts_set(ud->builder, "SrtLanguage");
2747                 language_opts_set(ud->builder, "PreferredLanguage");
2748                 srt_codeset_opts_set(ud->builder, "SrtCodeset");
2749                 title_opts_set(ud->builder, "title");
2750                 audio_track_opts_set(ud->builder, "AudioTrack", user_data);
2751                 subtitle_track_opts_set(ud->builder, "SubtitleTrack", user_data);
2752                 generic_opts_set(ud->builder, "VideoQualityGranularity", &vqual_granularity_opts);
2753                 generic_opts_set(ud->builder, "PtoPType", &point_to_point_opts);
2754                 generic_opts_set(ud->builder, "WhenComplete", &when_complete_opts);
2755                 generic_opts_set(ud->builder, "PicturePAR", &par_opts);
2756                 generic_opts_set(ud->builder, "PictureModulus", &alignment_opts);
2757                 generic_opts_set(ud->builder, "LoggingLevel", &logging_opts);
2758                 generic_opts_set(ud->builder, "LogLongevity", &log_longevity_opts);
2759                 generic_opts_set(ud->builder, "check_updates", &appcast_update_opts);
2760                 generic_opts_set(ud->builder, "FileFormat", &container_opts);
2761                 generic_opts_set(ud->builder, "PictureDeinterlace", &deint_opts);
2762                 generic_opts_set(ud->builder, "PictureDetelecine", &detel_opts);
2763                 generic_opts_set(ud->builder, "PictureDecomb", &decomb_opts);
2764                 generic_opts_set(ud->builder, "PictureDenoise", &denoise_opts);
2765                 generic_opts_set(ud->builder, "VideoEncoder", &vcodec_opts);
2766                 small_opts_set(ud->builder, "AudioEncoder", &acodec_opts);
2767                 small_opts_set(ud->builder, "x264_direct", &direct_opts);
2768                 small_opts_set(ud->builder, "x264_b_adapt", &badapt_opts);
2769                 small_opts_set(ud->builder, "x264_bpyramid", &bpyramid_opts);
2770                 small_opts_set(ud->builder, "x264_weighted_pframes", &weightp_opts);
2771                 small_opts_set(ud->builder, "x264_me", &me_opts);
2772                 small_opts_set(ud->builder, "x264_subme", &subme_opts);
2773                 small_opts_set(ud->builder, "x264_analyse", &analyse_opts);
2774                 small_opts_set(ud->builder, "x264_trellis", &trellis_opts);
2775         }
2776         else
2777         {
2778                 if (strcmp(name, "AudioBitrate") == 0)
2779                         audio_bitrate_opts_set(ud->builder, "AudioBitrate");
2780                 else if (strcmp(name, "AudioSamplerate") == 0)
2781                         audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
2782                 else if (strcmp(name, "VideoFramerate") == 0)
2783                         video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
2784                 else if (strcmp(name, "AudioMixdown") == 0)
2785                         mix_opts_set(ud->builder, "AudioMixdown");
2786                 else if (strcmp(name, "SrtLanguage") == 0)
2787                         language_opts_set(ud->builder, "SrtLanguage");
2788                 else if (strcmp(name, "PreferredLanguage") == 0)
2789                         language_opts_set(ud->builder, "PreferredLanguage");
2790                 else if (strcmp(name, "SrtCodeset") == 0)
2791                         srt_codeset_opts_set(ud->builder, "SrtCodeset");
2792                 else if (strcmp(name, "title") == 0)
2793                         title_opts_set(ud->builder, "title");
2794                 else if (strcmp(name, "SubtitleTrack") == 0)
2795                         subtitle_track_opts_set(ud->builder, "SubtitleTrack", user_data);
2796                 else if (strcmp(name, "AudioTrack") == 0)
2797                         audio_track_opts_set(ud->builder, "AudioTrack", user_data);
2798                 else
2799                         generic_opts_set(ud->builder, name, find_combo_table(name));
2800         }
2801         if (handler_id > 0)
2802         {
2803                 g_signal_handler_unblock ((gpointer)combo, handler_id);
2804         }
2805 }
2806         
2807 static void
2808 init_ui_combo_boxes(GtkBuilder *builder)
2809 {
2810         gint ii;
2811
2812         init_combo_box(builder, "AudioBitrate");
2813         init_combo_box(builder, "AudioSamplerate");
2814         init_combo_box(builder, "VideoFramerate");
2815         init_combo_box(builder, "AudioMixdown");
2816         init_combo_box(builder, "SrtLanguage");
2817         init_combo_box(builder, "PreferredLanguage");
2818         init_combo_box(builder, "SrtCodeset");
2819         init_combo_box(builder, "title");
2820         init_combo_box(builder, "AudioTrack");
2821         for (ii = 0; combo_name_map[ii].name != NULL; ii++)
2822         {
2823                 init_combo_box(builder, combo_name_map[ii].name);
2824         }
2825 }
2826         
2827 static const char * turbo_opts = 
2828         "ref=1:subme=2:me=dia:analyse=none:trellis=0:"
2829         "no-fast-pskip=0:8x8dct=0";
2830
2831 // Construct the x264 options string
2832 // The result is allocated, so someone must free it at some point.
2833 gchar*
2834 ghb_build_x264opts_string(GValue *settings)
2835 {
2836         gchar *result;
2837         gchar *opts = ghb_settings_get_string(settings, "x264Option");
2838         if (opts != NULL)
2839         {
2840                 result = opts;
2841         }
2842         else
2843         {
2844                 result = g_strdup("");
2845         }
2846         return result;
2847 }
2848
2849 void
2850 ghb_part_duration(gint tt, gint sc, gint ec, gint *hh, gint *mm, gint *ss)
2851 {
2852         hb_list_t  * list;
2853         hb_title_t * title;
2854     hb_chapter_t * chapter;
2855         gint count, c;
2856         gint64 duration;
2857         
2858         *hh = *mm = *ss = 0;
2859         if (h_scan == NULL) return;
2860         list = hb_get_titles( h_scan );
2861     title = (hb_title_t*)hb_list_item( list, tt );
2862         if (title == NULL) return;
2863
2864         *hh = title->hours;
2865         *mm = title->minutes;
2866         *ss = title->seconds;
2867
2868         count = hb_list_count(title->list_chapter);
2869         if (sc > count) sc = count;
2870         if (ec > count) ec = count;
2871
2872         if (sc == 1 && ec == count)
2873                 return;
2874
2875         duration = 0;
2876         for (c = sc; c <= ec; c++)
2877         {
2878                 chapter = hb_list_item(title->list_chapter, c-1);
2879                 duration += chapter->duration;
2880         }
2881
2882         *hh =   duration / 90000 / 3600;
2883         *mm = ((duration / 90000) % 3600) / 60;
2884         *ss =  (duration / 90000) % 60;
2885 }
2886
2887 void
2888 ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss)
2889 {
2890         hb_list_t  * list;
2891         hb_title_t * title;
2892     hb_chapter_t * chapter;
2893         gint count;
2894         
2895         g_debug("ghb_get_chapter_duration (title = %d)\n", ti);
2896         *hh = *mm = *ss = 0;
2897         if (h_scan == NULL) return;
2898         list = hb_get_titles( h_scan );
2899     title = (hb_title_t*)hb_list_item( list, ti );
2900         if (title == NULL) return;
2901         count = hb_list_count( title->list_chapter );
2902         if (ii >= count) return;
2903         chapter = hb_list_item(title->list_chapter, ii);
2904         if (chapter == NULL) return;
2905         *hh = chapter->hours;
2906         *mm = chapter->minutes;
2907         *ss = chapter->seconds;
2908 }
2909
2910 GValue*
2911 ghb_get_chapters(gint titleindex)
2912 {
2913         hb_list_t  * list;
2914         hb_title_t * title;
2915     hb_chapter_t * chapter;
2916         gint count, ii;
2917         GValue *chapters = NULL;
2918         
2919         g_debug("ghb_get_chapters (title = %d)\n", titleindex);
2920         if (h_scan == NULL) return NULL;
2921         list = hb_get_titles( h_scan );
2922     title = (hb_title_t*)hb_list_item( list, titleindex );
2923         if (title == NULL) return NULL;
2924         count = hb_list_count( title->list_chapter );
2925         chapters = ghb_array_value_new(count);
2926         for (ii = 0; ii < count; ii++)
2927         {
2928                 chapter = hb_list_item(title->list_chapter, ii);
2929                 if (chapter == NULL) break;
2930                 if (chapter->title == NULL || chapter->title[0] == 0)
2931                 {
2932                         gchar *str;
2933                         str = g_strdup_printf ("Chapter %2d", ii+1);
2934                         ghb_array_append(chapters, ghb_string_value_new(str));
2935                         g_free(str);
2936                 }
2937                 else 
2938                 {
2939                         ghb_array_append(chapters, ghb_string_value_new(chapter->title));
2940                 }
2941         }
2942         return chapters;
2943 }
2944
2945 gboolean
2946 ghb_ac3_in_audio_list(const GValue *audio_list)
2947 {
2948         gint count, ii;
2949
2950         count = ghb_array_len(audio_list);
2951         for (ii = 0; ii < count; ii++)
2952         {
2953                 GValue *asettings;
2954                 gint acodec;
2955
2956                 asettings = ghb_array_get_nth(audio_list, ii);
2957                 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
2958                 if (acodec & HB_ACODEC_AC3)
2959                         return TRUE;
2960         }
2961         return FALSE;
2962 }
2963
2964 static void
2965 audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
2966 {
2967         GtkTreeIter iter;
2968         GtkListStore *store;
2969         gchar *str;
2970         
2971         g_debug("audio_bitrate_opts_add ()\n");
2972
2973         if (rate < 8) return;
2974
2975         if (ghb_audio_bitrates[hb_audio_bitrates_count].string)
2976         {
2977                 g_free(ghb_audio_bitrates[hb_audio_bitrates_count].string);
2978         }
2979         ghb_audio_bitrates[hb_audio_bitrates_count].rate = rate;
2980         ghb_audio_bitrates[hb_audio_bitrates_count].string = 
2981                 g_strdup_printf("%d", rate);
2982         ghb_audio_bitrates_count = hb_audio_bitrates_count + 1;
2983
2984         store = get_combo_box_store(builder, name);
2985         if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
2986         {
2987                 str = g_strdup_printf ("<small>%d</small>", rate);
2988                 gtk_list_store_append(store, &iter);
2989                 gtk_list_store_set(store, &iter, 
2990                                                    0, str, 
2991                                                    1, TRUE, 
2992                                                    2, ghb_audio_bitrates[hb_audio_bitrates_count].string, 
2993                                                    3, (gdouble)rate, 
2994                                                    4, ghb_audio_bitrates[hb_audio_bitrates_count].string, 
2995                                                    -1);
2996                 g_free(str);
2997         }
2998 }
2999
3000 static void
3001 audio_bitrate_opts_clean(
3002         GtkBuilder *builder, 
3003         const gchar *name, 
3004         gint first_rate, 
3005         gint last_rate)
3006 {
3007         GtkTreeIter iter;
3008         GtkListStore *store;
3009         gdouble ivalue;
3010         gboolean done = FALSE;
3011         gint ii = 0;
3012         guint last = (guint)last_rate;
3013         guint first = (guint)first_rate;
3014         
3015         ghb_audio_bitrates_count = hb_audio_bitrates_count;
3016
3017         g_debug("audio_bitrate_opts_clean ()\n");
3018         store = get_combo_box_store(builder, name);
3019         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
3020         {
3021                 do
3022                 {
3023                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
3024                         if (search_rates(
3025                                 ghb_audio_bitrates, ivalue, ghb_audio_bitrates_count) < 0)
3026                         {
3027                                 done = !gtk_list_store_remove(store, &iter);
3028                         }
3029                         else if (ivalue < first || ivalue > last)
3030                         {
3031                                 ii++;
3032                                 gtk_list_store_set(store, &iter, 1, FALSE, -1);
3033                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
3034                         }
3035                         else
3036                         {
3037                                 ii++;
3038                                 gtk_list_store_set(store, &iter, 1, TRUE, -1);
3039                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
3040                         }
3041                 } while (!done);
3042         }
3043 }
3044
3045 static void
3046 audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
3047 {
3048         GtkTreeIter iter;
3049         GtkListStore *store;
3050         gint ii;
3051         gchar *str;
3052         
3053         ghb_audio_bitrates_count = hb_audio_bitrates_count;
3054         ghb_audio_bitrates = calloc(hb_audio_bitrates_count+1, sizeof(hb_rate_t));
3055
3056         for (ii = 0; ii < hb_audio_bitrates_count; ii++)
3057         {
3058                 ghb_audio_bitrates[ii] = hb_audio_bitrates[ii];
3059         }
3060
3061         g_debug("audio_bitrate_opts_set ()\n");
3062         store = get_combo_box_store(builder, name);
3063         gtk_list_store_clear(store);
3064         for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
3065         {
3066                 gtk_list_store_append(store, &iter);
3067                 str = g_strdup_printf ("<small>%s</small>", 
3068                         ghb_audio_bitrates[ii].string);
3069                 gtk_list_store_set(store, &iter, 
3070                                                    0, str,
3071                                                    1, TRUE, 
3072                                                    2, ghb_audio_bitrates[ii].string, 
3073                                                    3, (gdouble)ghb_audio_bitrates[ii].rate, 
3074                                                    4, ghb_audio_bitrates[ii].string, 
3075                                                    -1);
3076                 g_free(str);
3077         }
3078 }
3079
3080 void
3081 ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate)
3082 {
3083         audio_bitrate_opts_add(builder, "AudioBitrate", bitrate);
3084 }
3085
3086 void
3087 ghb_set_default_bitrate_opts(
3088         GtkBuilder *builder, 
3089         gint first_rate, 
3090         gint last_rate)
3091 {
3092         audio_bitrate_opts_clean(builder, "AudioBitrate", first_rate, last_rate);
3093 }
3094
3095 static ghb_status_t hb_status;
3096
3097 void
3098 ghb_combo_init(signal_user_data_t *ud)
3099 {
3100         // Set up the list model for the combos
3101         init_ui_combo_boxes(ud->builder);
3102         // Populate all the combos
3103         ghb_update_ui_combo_box(ud, NULL, 0, TRUE);
3104 }
3105
3106 void
3107 ghb_backend_init(gint debug)
3108 {
3109     /* Init libhb */
3110     h_scan = hb_init( debug, 0 );
3111     h_queue = hb_init( debug, 0 );
3112 }
3113
3114 void
3115 ghb_backend_close()
3116 {
3117         hb_close(&h_queue);
3118         hb_close(&h_scan);
3119         hb_global_close();
3120 }
3121
3122 void ghb_backend_scan_stop()
3123 {
3124     hb_scan_stop( h_scan );
3125 }
3126
3127 void
3128 ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count, uint64_t min_duration)
3129 {
3130     hb_scan( h_scan, path, titleindex, preview_count, 1, min_duration );
3131         hb_status.scan.state |= GHB_STATE_SCANNING;
3132         // initialize count and cur to something that won't cause FPE
3133         // when computing progress
3134         hb_status.scan.title_count = 1;
3135         hb_status.scan.title_cur = 0;
3136 }
3137
3138 void
3139 ghb_backend_queue_scan(const gchar *path, gint titlenum)
3140 {
3141         g_debug("ghb_backend_queue_scan()");
3142         hb_scan( h_queue, path, titlenum, 10, 0, 0 );
3143         hb_status.queue.state |= GHB_STATE_SCANNING;
3144 }
3145
3146 gint
3147 ghb_get_scan_state()
3148 {
3149         return hb_status.scan.state;
3150 }
3151
3152 gint
3153 ghb_get_queue_state()
3154 {
3155         return hb_status.queue.state;
3156 }
3157
3158 void
3159 ghb_clear_scan_state(gint state)
3160 {
3161         hb_status.scan.state &= ~state;
3162 }
3163
3164 void
3165 ghb_clear_queue_state(gint state)
3166 {
3167         hb_status.queue.state &= ~state;
3168 }
3169
3170 void
3171 ghb_set_scan_state(gint state)
3172 {
3173         hb_status.scan.state |= state;
3174 }
3175
3176 void
3177 ghb_set_queue_state(gint state)
3178 {
3179         hb_status.queue.state |= state;
3180 }
3181
3182 void
3183 ghb_get_status(ghb_status_t *status)
3184 {
3185         memcpy(status, &hb_status, sizeof(ghb_status_t));
3186 }
3187
3188 void 
3189 ghb_track_status()
3190 {
3191     hb_state_t s_scan;
3192     hb_state_t s_queue;
3193
3194         if (h_scan == NULL) return;
3195     hb_get_state( h_scan, &s_scan );
3196         switch( s_scan.state )
3197     {
3198 #define p s_scan.param.scanning
3199         case HB_STATE_SCANNING:
3200                 {
3201                         hb_status.scan.state |= GHB_STATE_SCANNING;
3202                         hb_status.scan.title_count = p.title_count;
3203                         hb_status.scan.title_cur = p.title_cur;
3204                 } break;
3205 #undef p
3206
3207         case HB_STATE_SCANDONE:
3208         {
3209                         hb_status.scan.state &= ~GHB_STATE_SCANNING;
3210                         hb_status.scan.state |= GHB_STATE_SCANDONE;
3211         } break;
3212
3213 #define p s_scan.param.working
3214         case HB_STATE_WORKING:
3215                         hb_status.scan.state |= GHB_STATE_WORKING;
3216                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
3217                         hb_status.scan.job_cur = p.job_cur;
3218                         hb_status.scan.job_count = p.job_count;
3219                         hb_status.scan.progress = p.progress;
3220                         hb_status.scan.rate_cur = p.rate_cur;
3221                         hb_status.scan.rate_avg = p.rate_avg;
3222                         hb_status.scan.hours = p.hours;
3223                         hb_status.scan.minutes = p.minutes;
3224                         hb_status.scan.seconds = p.seconds;
3225                         hb_status.scan.unique_id = p.sequence_id & 0xFFFFFF;
3226             break;
3227 #undef p
3228
3229         case HB_STATE_PAUSED:
3230                         hb_status.scan.state |= GHB_STATE_PAUSED;
3231             break;
3232                                 
3233         case HB_STATE_MUXING:
3234         {
3235                         hb_status.scan.state |= GHB_STATE_MUXING;
3236         } break;
3237
3238 #define p s_scan.param.workdone
3239         case HB_STATE_WORKDONE:
3240                 {
3241             hb_job_t *job;
3242
3243                         hb_status.scan.state |= GHB_STATE_WORKDONE;
3244                         hb_status.scan.state &= ~GHB_STATE_MUXING;
3245                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
3246                         hb_status.scan.state &= ~GHB_STATE_WORKING;
3247                         switch (p.error)
3248                         {
3249                         case HB_ERROR_NONE:
3250                                 hb_status.scan.error = GHB_ERROR_NONE;
3251                                 break;
3252                         case HB_ERROR_CANCELED:
3253                                 hb_status.scan.error = GHB_ERROR_CANCELED;
3254                                 break;
3255                         default:
3256                                 hb_status.scan.error = GHB_ERROR_FAIL;
3257                                 break;
3258                         }
3259                         // Delete all remaining jobs of this encode.
3260                         // An encode can be composed of multiple associated jobs.
3261                         // When a job is stopped, libhb removes it from the job list,
3262                         // but does not remove other jobs that may be associated with it.
3263                         // Associated jobs are taged in the sequence id.
3264             while ((job = hb_job(h_scan, 0)) != NULL) 
3265                 hb_rem( h_scan, job );
3266                 } break;
3267 #undef p
3268     }
3269     hb_get_state( h_queue, &s_queue );
3270         switch( s_queue.state )
3271     {
3272 #define p s_queue.param.scanning
3273         case HB_STATE_SCANNING:
3274                 {
3275                         hb_status.queue.state |= GHB_STATE_SCANNING;
3276                         hb_status.queue.title_count = p.title_count;
3277                         hb_status.queue.title_cur = p.title_cur;
3278                 } break;
3279 #undef p
3280
3281         case HB_STATE_SCANDONE:
3282         {
3283                         hb_status.queue.state &= ~GHB_STATE_SCANNING;
3284                         hb_status.queue.state |= GHB_STATE_SCANDONE;
3285         } break;
3286
3287 #define p s_queue.param.working
3288         case HB_STATE_WORKING:
3289                         hb_status.queue.state |= GHB_STATE_WORKING;
3290                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
3291                         hb_status.queue.state &= ~GHB_STATE_SEARCHING;
3292                         hb_status.queue.job_cur = p.job_cur;
3293                         hb_status.queue.job_count = p.job_count;
3294                         hb_status.queue.progress = p.progress;
3295                         hb_status.queue.rate_cur = p.rate_cur;
3296                         hb_status.queue.rate_avg = p.rate_avg;
3297                         hb_status.queue.hours = p.hours;
3298                         hb_status.queue.minutes = p.minutes;
3299                         hb_status.queue.seconds = p.seconds;
3300                         hb_status.queue.unique_id = p.sequence_id & 0xFFFFFF;
3301             break;
3302
3303         case HB_STATE_SEARCHING:
3304                         hb_status.queue.state |= GHB_STATE_SEARCHING;
3305                         hb_status.queue.state &= ~GHB_STATE_WORKING;
3306                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
3307                         hb_status.queue.job_cur = p.job_cur;
3308                         hb_status.queue.job_count = p.job_count;
3309                         hb_status.queue.progress = p.progress;
3310                         hb_status.queue.rate_cur = p.rate_cur;
3311                         hb_status.queue.rate_avg = p.rate_avg;
3312                         hb_status.queue.hours = p.hours;
3313                         hb_status.queue.minutes = p.minutes;
3314                         hb_status.queue.seconds = p.seconds;
3315                         hb_status.queue.unique_id = p.sequence_id & 0xFFFFFF;
3316             break;
3317 #undef p
3318
3319         case HB_STATE_PAUSED:
3320                         hb_status.queue.state |= GHB_STATE_PAUSED;
3321             break;
3322                                 
3323         case HB_STATE_MUXING:
3324         {
3325                         hb_status.queue.state |= GHB_STATE_MUXING;
3326         } break;
3327
3328 #define p s_queue.param.workdone
3329         case HB_STATE_WORKDONE:
3330                 {
3331             hb_job_t *job;
3332
3333                         hb_status.queue.state |= GHB_STATE_WORKDONE;
3334                         hb_status.queue.state &= ~GHB_STATE_MUXING;
3335                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
3336                         hb_status.queue.state &= ~GHB_STATE_WORKING;
3337                         hb_status.queue.state &= ~GHB_STATE_SEARCHING;
3338                         switch (p.error)
3339                         {
3340                         case HB_ERROR_NONE:
3341                                 hb_status.queue.error = GHB_ERROR_NONE;
3342                                 break;
3343                         case HB_ERROR_CANCELED:
3344                                 hb_status.queue.error = GHB_ERROR_CANCELED;
3345                                 break;
3346                         default:
3347                                 hb_status.queue.error = GHB_ERROR_FAIL;
3348                                 break;
3349                         }
3350                         // Delete all remaining jobs of this encode.
3351                         // An encode can be composed of multiple associated jobs.
3352                         // When a job is stopped, libhb removes it from the job list,
3353                         // but does not remove other jobs that may be associated with it.
3354                         // Associated jobs are taged in the sequence id.
3355             while ((job = hb_job(h_queue, 0)) != NULL) 
3356                 hb_rem( h_queue, job );
3357                 } break;
3358 #undef p
3359     }
3360 }
3361
3362 gboolean
3363 ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
3364 {
3365         hb_list_t  * list;
3366         hb_title_t * title;
3367         
3368     if (h_scan == NULL) return FALSE;
3369         list = hb_get_titles( h_scan );
3370         if( !hb_list_count( list ) )
3371         {
3372                 /* No valid title, stop right there */
3373                 return FALSE;
3374         }
3375
3376         title = hb_list_item( list, titleindex );
3377         if (title == NULL) return FALSE;        // Bad titleindex
3378         tinfo->index = titleindex;
3379         tinfo->width = title->width;
3380         tinfo->height = title->height;
3381         memcpy(tinfo->crop, title->crop, 4 * sizeof(int));
3382         // Don't allow crop to 0
3383         if (title->crop[0] + title->crop[1] >= title->height)
3384                 title->crop[0] = title->crop[1] = 0;
3385         if (title->crop[2] + title->crop[3] >= title->width)
3386                 title->crop[2] = title->crop[3] = 0;
3387         tinfo->num_chapters = hb_list_count(title->list_chapter);
3388         tinfo->rate_base = title->rate_base;
3389         tinfo->rate = title->rate;
3390         tinfo->interlaced = title->detected_interlacing;
3391         hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), 
3392                                 title->width * title->pixel_aspect_width, 
3393                                 title->height * title->pixel_aspect_height);
3394         tinfo->hours = title->hours;
3395         tinfo->minutes = title->minutes;
3396         tinfo->seconds = title->seconds;
3397         tinfo->duration = title->duration;
3398
3399         tinfo->angle_count = title->angle_count;
3400         tinfo->path = title->path;
3401         tinfo->name = title->name;
3402         tinfo->type = title->type;
3403         return TRUE;
3404 }
3405
3406 hb_audio_config_t*
3407 ghb_get_scan_audio_info(gint titleindex, gint audioindex)
3408 {
3409     hb_audio_config_t *aconfig;
3410         
3411         aconfig = get_hb_audio(h_scan, titleindex, audioindex);
3412         return aconfig;
3413 }
3414
3415 gboolean
3416 ghb_audio_is_passthru(gint acodec)
3417 {
3418         g_debug("ghb_audio_is_passthru () \n");
3419         return (acodec & HB_ACODEC_PASS_FLAG) != 0;
3420 }
3421
3422 gboolean
3423 ghb_audio_can_passthru(gint acodec)
3424 {
3425         g_debug("ghb_audio_can_passthru () \n");
3426         return (acodec & HB_ACODEC_PASS_MASK) != 0;
3427 }
3428
3429 gint
3430 ghb_get_default_acodec()
3431 {
3432         return HB_ACODEC_FAAC;
3433 }
3434
3435 static void
3436 picture_settings_deps(signal_user_data_t *ud)
3437 {
3438         gboolean autoscale, keep_aspect, enable_keep_aspect;
3439         gboolean enable_scale_width, enable_scale_height;
3440         gboolean enable_disp_width, enable_disp_height, enable_par;
3441         gint pic_par;
3442         GtkWidget *widget;
3443
3444         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
3445         if (pic_par == 1)
3446         {
3447                 ghb_ui_update(ud, "autoscale", ghb_boolean_value(TRUE));
3448                 ghb_ui_update(ud, "PictureModulus", ghb_int_value(2));
3449                 ghb_ui_update(ud, "PictureLooseCrop", ghb_boolean_value(TRUE));
3450         }
3451         enable_keep_aspect = (pic_par != 1 && pic_par != 2);
3452         if (!enable_keep_aspect)
3453         {
3454                 ghb_ui_update(ud, "PictureKeepRatio", ghb_boolean_value(TRUE));
3455         }
3456         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
3457         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
3458
3459         enable_scale_width = !autoscale && (pic_par != 1);
3460         enable_scale_height = !autoscale && (pic_par != 1);
3461         enable_disp_width = (pic_par == 3) && !keep_aspect;
3462         enable_par = (pic_par == 3) && !keep_aspect;
3463         enable_disp_height = FALSE;
3464
3465         widget = GHB_WIDGET(ud->builder, "PictureModulus");
3466         gtk_widget_set_sensitive(widget, pic_par != 1);
3467         widget = GHB_WIDGET(ud->builder, "PictureLooseCrop");
3468         gtk_widget_set_sensitive(widget, pic_par != 1);
3469         widget = GHB_WIDGET(ud->builder, "scale_width");
3470         gtk_widget_set_sensitive(widget, enable_scale_width);
3471         widget = GHB_WIDGET(ud->builder, "scale_height");
3472         gtk_widget_set_sensitive(widget, enable_scale_height);
3473         widget = GHB_WIDGET(ud->builder, "PictureDisplayWidth");
3474         gtk_widget_set_sensitive(widget, enable_disp_width);
3475         widget = GHB_WIDGET(ud->builder, "PictureDisplayHeight");
3476         gtk_widget_set_sensitive(widget, enable_disp_height);
3477         widget = GHB_WIDGET(ud->builder, "PicturePARWidth");
3478         gtk_widget_set_sensitive(widget, enable_par);
3479         widget = GHB_WIDGET(ud->builder, "PicturePARHeight");
3480         gtk_widget_set_sensitive(widget, enable_par);
3481         widget = GHB_WIDGET(ud->builder, "PictureKeepRatio");
3482         gtk_widget_set_sensitive(widget, enable_keep_aspect);
3483         widget = GHB_WIDGET(ud->builder, "autoscale");
3484         gtk_widget_set_sensitive(widget, pic_par != 1);
3485 }
3486
3487 void
3488 ghb_set_scale(signal_user_data_t *ud, gint mode)
3489 {
3490         hb_list_t  * list;
3491         hb_title_t * title;
3492         hb_job_t   * job;
3493         gboolean keep_aspect;
3494         gint pic_par;
3495         gboolean autocrop, autoscale, noscale;
3496         gint crop[4], width, height, par_width, par_height;
3497         gint crop_width, crop_height;
3498         gint aspect_n, aspect_d;
3499         gboolean keep_width = (mode & GHB_PIC_KEEP_WIDTH);
3500         gboolean keep_height = (mode & GHB_PIC_KEEP_HEIGHT);
3501         gint step;
3502         GtkWidget *widget;
3503         gint mod;
3504         gint max_width = 0;
3505         gint max_height = 0;
3506         
3507         g_debug("ghb_set_scale ()\n");
3508         picture_settings_deps(ud);
3509         if (h_scan == NULL) return;
3510         list = hb_get_titles( h_scan );
3511         if( !hb_list_count( list ) )
3512         {
3513                 /* No valid title, stop right there */
3514                 return;
3515         }
3516         gint titleindex;
3517
3518         titleindex = ghb_settings_combo_int(ud->settings, "title");
3519         title = hb_list_item( list, titleindex );
3520         if (title == NULL) return;
3521         job   = title->job;
3522         if (job == NULL) return;
3523
3524         if (ud->scale_busy) return;
3525         ud->scale_busy = TRUE;
3526
3527         // First configure widgets
3528         mod = ghb_settings_combo_int(ud->settings, "PictureModulus");
3529         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
3530         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
3531         autocrop = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop");
3532         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
3533         // "Noscale" is a flag that says we prefer to crop extra to satisfy
3534         // alignment constraints rather than scaling to satisfy them.
3535         noscale = ghb_settings_get_boolean(ud->settings, "PictureLooseCrop");
3536         // Align dimensions to either 16 or 2 pixels
3537         // The scaler crashes if the dimensions are not divisible by 2
3538         // x264 also will not accept dims that are not multiple of 2
3539         if (autoscale)
3540         {
3541                 keep_width = FALSE;
3542                 keep_height = FALSE;
3543         }
3544         // Step needs to be at least 2 because odd widths cause scaler crash
3545         step = mod;
3546         widget = GHB_WIDGET (ud->builder, "scale_width");
3547         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3548         widget = GHB_WIDGET (ud->builder, "scale_height");
3549         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3550         if (noscale)
3551         {
3552                 widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
3553                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3554                 widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
3555                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3556                 widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
3557                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3558                 widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
3559                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3560         }
3561         else
3562         {
3563                 widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
3564                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3565                 widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
3566                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3567                 widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
3568                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3569                 widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
3570                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3571         }
3572         ghb_title_info_t tinfo;
3573         ghb_get_title_info (&tinfo, titleindex);
3574         if (autocrop)
3575         {
3576                 crop[0] = tinfo.crop[0];
3577                 crop[1] = tinfo.crop[1];
3578                 crop[2] = tinfo.crop[2];
3579                 crop[3] = tinfo.crop[3];
3580                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(crop[0]));
3581                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(crop[1]));
3582                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(crop[2]));
3583                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(crop[3]));
3584         }
3585         else
3586         {
3587                 crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
3588                 crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
3589                 crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
3590                 crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
3591         }
3592         if (noscale)
3593         {
3594                 gint need1, need2;
3595
3596                 // Adjust the cropping to accomplish the desired width and height
3597                 crop_width = tinfo.width - crop[2] - crop[3];
3598                 crop_height = tinfo.height - crop[0] - crop[1];
3599                 width = MOD_DOWN(crop_width, mod);
3600                 height = MOD_DOWN(crop_height, mod);
3601
3602                 need1 = (crop_height - height) / 2;
3603                 need2 = crop_height - height - need1;
3604                 crop[0] += need1;
3605                 crop[1] += need2;
3606                 need1 = (crop_width - width) / 2;
3607                 need2 = crop_width - width - need1;
3608                 crop[2] += need1;
3609                 crop[3] += need2;
3610                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(crop[0]));
3611                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(crop[1]));
3612                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(crop[2]));
3613                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(crop[3]));
3614         }
3615         hb_reduce(&aspect_n, &aspect_d, 
3616                                 title->width * title->pixel_aspect_width, 
3617                                 title->height * title->pixel_aspect_height);
3618         crop_width = title->width - crop[2] - crop[3];
3619         crop_height = title->height - crop[0] - crop[1];
3620         if (autoscale)
3621         {
3622                 width = crop_width;
3623                 height = crop_height;
3624         }
3625         else
3626         {
3627                 width = ghb_settings_get_int(ud->settings, "scale_width");
3628                 height = ghb_settings_get_int(ud->settings, "scale_height");
3629                 if (mode & GHB_PIC_USE_MAX)
3630                 {
3631                         max_width = MOD_DOWN(
3632                                 ghb_settings_get_int(ud->settings, "PictureWidth"), mod);
3633                         max_height = MOD_DOWN(
3634                                 ghb_settings_get_int(ud->settings, "PictureHeight"), mod);
3635                 }
3636         }
3637         g_debug("max_width %d, max_height %d\n", max_width, max_height);
3638
3639         if (width < 16)
3640                 width = title->width - crop[2] - crop[3];
3641         if (height < 16)
3642                 height = title->height - crop[0] - crop[1];
3643
3644         width = MOD_ROUND(width, mod);
3645         height = MOD_ROUND(height, mod);
3646
3647         job->anamorphic.mode = pic_par;
3648         if (pic_par)
3649         {
3650                 // The scaler crashes if the dimensions are not divisible by 2
3651                 // Align mod 2.  And so does something in x264_encoder_headers()
3652                 job->modulus = mod;
3653                 job->anamorphic.par_width = title->pixel_aspect_width;
3654                 job->anamorphic.par_height = title->pixel_aspect_height;
3655                 job->anamorphic.dar_width = 0;
3656                 job->anamorphic.dar_height = 0;
3657
3658                 if (keep_height && pic_par == 2)
3659                         width = ((double)height * crop_width / crop_height);
3660                 job->width = width;
3661                 job->height = height;
3662                 job->maxWidth = max_width;
3663                 job->maxHeight = max_height;
3664                 job->crop[0] = crop[0]; job->crop[1] = crop[1];
3665                 job->crop[2] = crop[2]; job->crop[3] = crop[3];
3666                 if (job->anamorphic.mode == 3 && !keep_aspect)
3667                 {
3668                         job->anamorphic.keep_display_aspect = 0;
3669                         if (mode & GHB_PIC_KEEP_PAR)
3670                         {
3671                                 job->anamorphic.par_width = 
3672                                         ghb_settings_get_int(ud->settings, "PicturePARWidth");
3673                                 job->anamorphic.par_height = 
3674                                         ghb_settings_get_int(ud->settings, "PicturePARHeight");
3675                         }
3676                         else
3677                         {
3678                                 job->anamorphic.dar_width = 
3679                                         ghb_settings_get_int(ud->settings, 
3680                                                                                 "PictureDisplayWidth");
3681                                 job->anamorphic.dar_height = height;
3682                         }
3683                 }
3684                 else
3685                 {
3686                         job->anamorphic.keep_display_aspect = 1;
3687                 }
3688                 // hb_set_anamorphic_size will adjust par, dar, and width/height
3689                 // to conform to job parameters that have been set, including 
3690                 // maxWidth and maxHeight
3691                 hb_set_anamorphic_size( job, &width, &height, 
3692                                                                 &par_width, &par_height );
3693                 if (job->anamorphic.mode == 3 && !keep_aspect && 
3694                         mode & GHB_PIC_KEEP_PAR)
3695                 {
3696                         // hb_set_anamorphic_size reduces the par, which we
3697                         // don't want in this case because the user is
3698                         // explicitely specifying it.
3699                         par_width = ghb_settings_get_int(ud->settings, 
3700                                                                                         "PicturePARWidth");
3701                         par_height = ghb_settings_get_int(ud->settings, 
3702                                                                                                 "PicturePARHeight");
3703                 }
3704         }
3705         else 
3706         {
3707                 // Adjust dims according to max values
3708                 if (max_height)
3709                         height = MIN(height, max_height);
3710                 if (max_width)
3711                         width = MIN(width, max_width);
3712
3713                 if (keep_aspect)
3714                 {
3715                         gdouble par;
3716                         gint new_width, new_height;
3717                         
3718                         // Compute pixel aspect ration.  
3719                         par = (gdouble)(title->height * aspect_n) / (title->width * aspect_d);
3720                         // Must scale so that par becomes 1:1
3721                         // Try to keep largest dimension
3722                         new_height = (crop_height * ((gdouble)width/crop_width) / par);
3723                         new_width = (crop_width * ((gdouble)height/crop_height) * par);
3724
3725                         if (max_width && new_width > max_width)
3726                         {
3727                                 height = new_height;
3728                         }
3729                         else if (max_height && new_height > max_height)
3730                         {
3731                                 width = new_width;
3732                         }
3733                         else if (keep_width)
3734                         {
3735                                 height = new_height;
3736                         }
3737                         else if (keep_height)
3738                         {
3739                                 width = new_width;
3740                         }
3741                         else if (width > new_width)
3742                         {
3743                                 height = new_height;
3744                         }
3745                         else
3746                         {
3747                                 width = new_width;
3748                         }
3749                         g_debug("new w %d h %d\n", width, height);
3750                 }
3751                 width = MOD_ROUND(width, mod);
3752                 height = MOD_ROUND(height, mod);
3753                 if (max_height)
3754                         height = MIN(height, max_height);
3755                 if (max_width)
3756                         width = MIN(width, max_width);
3757                 par_width = par_height = 1;
3758         }
3759         ghb_ui_update(ud, "scale_width", ghb_int64_value(width));
3760         ghb_ui_update(ud, "scale_height", ghb_int64_value(height));
3761
3762         gint disp_width, dar_width, dar_height;
3763         gchar *str;
3764
3765         disp_width = (gdouble)(width * par_width / par_height) + 0.5;
3766         hb_reduce(&dar_width, &dar_height, disp_width, height);
3767                 
3768         gint iaspect = dar_width * 9 / dar_height;
3769         if (dar_width > 2 * dar_height)
3770         {
3771                 str = g_strdup_printf("%.2f : 1", (gdouble)dar_width / dar_height);
3772         }
3773         else if (iaspect <= 16 && iaspect >= 15)
3774         {
3775                 str = g_strdup_printf("%.2f : 9", (gdouble)dar_width * 9 / dar_height);
3776         }
3777         else if (iaspect <= 12 && iaspect >= 11)
3778         {
3779                 str = g_strdup_printf("%.2f : 3", (gdouble)dar_width * 3 / dar_height);
3780         }
3781         else
3782         {
3783                 str = g_strdup_printf("%d : %d", dar_width, dar_height);
3784         }
3785         ghb_ui_update(ud, "display_aspect", ghb_string_value(str));
3786         g_free(str);
3787         ghb_ui_update(ud, "PicturePARWidth", ghb_int64_value(par_width));
3788         ghb_ui_update(ud, "PicturePARHeight", ghb_int64_value(par_height));
3789         ghb_ui_update(ud, "PictureDisplayWidth", ghb_int64_value(disp_width));
3790         ghb_ui_update(ud, "PictureDisplayHeight", ghb_int64_value(height));
3791         ud->scale_busy = FALSE;
3792 }
3793
3794 static void
3795 set_preview_job_settings(hb_job_t *job, GValue *settings)
3796 {
3797         job->crop[0] = ghb_settings_get_int(settings, "PictureTopCrop");
3798         job->crop[1] = ghb_settings_get_int(settings, "PictureBottomCrop");
3799         job->crop[2] = ghb_settings_get_int(settings, "PictureLeftCrop");
3800         job->crop[3] = ghb_settings_get_int(settings, "PictureRightCrop");
3801
3802         job->anamorphic.mode = ghb_settings_combo_int(settings, "PicturePAR");
3803         job->modulus = 
3804                 ghb_settings_combo_int(settings, "PictureModulus");
3805         job->width = ghb_settings_get_int(settings, "scale_width");
3806         job->height = ghb_settings_get_int(settings, "scale_height");
3807         if (ghb_settings_get_boolean(settings, "show_crop"))
3808         {
3809                 gdouble xscale = (gdouble)job->width / 
3810                         (gdouble)(job->title->width - job->crop[2] - job->crop[3]);
3811                 gdouble yscale = (gdouble)job->height / 
3812                         (gdouble)(job->title->height - job->crop[0] - job->crop[1]);
3813         
3814                 job->width += xscale * (job->crop[2] + job->crop[3]);
3815                 job->height += yscale * (job->crop[0] + job->crop[1]);
3816                 job->crop[0] = 0;
3817                 job->crop[1] = 0;
3818                 job->crop[2] = 0;
3819                 job->crop[3] = 0;
3820                 job->modulus = 2;
3821         }
3822
3823         gboolean decomb_deint = ghb_settings_get_boolean(settings, "PictureDecombDeinterlace");
3824         if (decomb_deint)
3825         {
3826                 gint decomb = ghb_settings_combo_int(settings, "PictureDecomb");
3827                 job->deinterlace = (decomb == 0) ? 0 : 1;
3828         }
3829         else
3830         {
3831                 gint deint = ghb_settings_combo_int(settings, "PictureDeinterlace");
3832                 job->deinterlace = (deint == 0) ? 0 : 1;
3833         }
3834
3835         gboolean keep_aspect;
3836         keep_aspect = ghb_settings_get_boolean(settings, "PictureKeepRatio");
3837         if (job->anamorphic.mode)
3838         {
3839                 job->anamorphic.par_width = job->title->pixel_aspect_width;
3840                 job->anamorphic.par_height = job->title->pixel_aspect_height;
3841                 job->anamorphic.dar_width = 0;
3842                 job->anamorphic.dar_height = 0;
3843
3844                 if (job->anamorphic.mode == 3 && !keep_aspect)
3845                 {
3846                         job->anamorphic.keep_display_aspect = 0;
3847                         job->anamorphic.par_width = 
3848                                 ghb_settings_get_int(settings, "PicturePARWidth");
3849                         job->anamorphic.par_height = 
3850                                 ghb_settings_get_int(settings, "PicturePARHeight");
3851                 }
3852                 else
3853                 {
3854                         job->anamorphic.keep_display_aspect = 1;
3855                 }
3856         }
3857 }
3858
3859 gboolean
3860 ghb_validate_filter_string(const gchar *str, gint max_fields)
3861 {
3862         gint fields = 0;
3863         gchar *end;
3864         gdouble val;
3865
3866         if (str == NULL || *str == 0) return TRUE;
3867         while (*str)
3868         {
3869                 val = g_strtod(str, &end);
3870                 if (str != end)
3871                 { // Found a numeric value
3872                         fields++;
3873                         // negative max_fields means infinate
3874                         if (max_fields >= 0 && fields > max_fields) return FALSE;
3875                         if (*end == 0)
3876                                 return TRUE;
3877                         if (*end != ':')
3878                                 return FALSE;
3879                         str = end + 1;
3880                 }
3881                 else
3882                         return FALSE;
3883         }
3884         return FALSE;
3885 }
3886
3887 gboolean
3888 ghb_validate_filters(signal_user_data_t *ud)
3889 {
3890         gchar *str;
3891         gint index;
3892         gchar *message;
3893
3894         gboolean decomb_deint = ghb_settings_get_boolean(ud->settings, "PictureDecombDeinterlace");
3895         // deinte
3896         index = ghb_settings_combo_int(ud->settings, "PictureDeinterlace");
3897         if (!decomb_deint && index == 1)
3898         {
3899                 str = ghb_settings_get_string(ud->settings, "PictureDeinterlaceCustom");
3900                 if (!ghb_validate_filter_string(str, -1))
3901                 {
3902                         message = g_strdup_printf(
3903                                                 "Invalid Deinterlace Settings:\n\n%s\n",
3904                                                 str);
3905                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3906                         g_free(message);
3907                         g_free(str);
3908                         return FALSE;
3909                 }
3910                 g_free(str);
3911         }
3912         // detel
3913         index = ghb_settings_combo_int(ud->settings, "PictureDetelecine");
3914         if (index == 1)
3915         {
3916                 str = ghb_settings_get_string(ud->settings, "PictureDetelecineCustom");
3917                 if (!ghb_validate_filter_string(str, -1))
3918                 {
3919                         message = g_strdup_printf(
3920                                                 "Invalid Detelecine Settings:\n\n%s\n",
3921                                                 str);
3922                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3923                         g_free(message);
3924                         g_free(str);
3925                         return FALSE;
3926                 }
3927                 g_free(str);
3928         }
3929         // decomb
3930         index = ghb_settings_combo_int(ud->settings, "PictureDecomb");
3931         if (decomb_deint && index == 1)
3932         {
3933                 str = ghb_settings_get_string(ud->settings, "PictureDecombCustom");
3934                 if (!ghb_validate_filter_string(str, -1))
3935                 {
3936                         message = g_strdup_printf(
3937                                                 "Invalid Decomb Settings:\n\n%s\n",
3938                                                 str);
3939                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3940                         g_free(message);
3941                         g_free(str);
3942                         return FALSE;
3943                 }
3944                 g_free(str);
3945         }
3946         // denois
3947         index = ghb_settings_combo_int(ud->settings, "PictureDenoise");
3948         if (index == 1)
3949         {
3950                 str = ghb_settings_get_string(ud->settings, "PictureDenoiseCustom");
3951                 if (!ghb_validate_filter_string(str, -1))
3952                 {
3953                         message = g_strdup_printf(
3954                                                 "Invalid Denoise Settings:\n\n%s\n",
3955                                                 str);
3956                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3957                         g_free(str);
3958                         g_free(message);
3959                         return FALSE;
3960                 }
3961                 g_free(str);
3962         }
3963         return TRUE;
3964 }
3965
3966 gboolean
3967 ghb_validate_video(signal_user_data_t *ud)
3968 {
3969         gint vcodec, mux;
3970         gchar *message;
3971
3972         mux = ghb_settings_combo_int(ud->settings, "FileFormat");
3973         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
3974         if ((mux == HB_MUX_MP4) && (vcodec == HB_VCODEC_THEORA))
3975         {
3976                 // mp4/theora combination is not supported.
3977                 message = g_strdup_printf(
3978                                         "Theora is not supported in the MP4 container.\n\n"
3979                                         "You should choose a different video codec or container.\n"
3980                                         "If you continue, FFMPEG will be chosen for you.");
3981                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3982                 {
3983                         g_free(message);
3984                         return FALSE;
3985                 }
3986                 g_free(message);
3987                 vcodec = HB_VCODEC_FFMPEG;
3988                 ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
3989         }
3990         return TRUE;
3991 }
3992
3993 gboolean
3994 ghb_validate_subtitles(signal_user_data_t *ud)
3995 {
3996         hb_list_t  * list;
3997         hb_title_t * title;
3998         gchar *message;
3999
4000         if (h_scan == NULL) return FALSE;
4001         list = hb_get_titles( h_scan );
4002         if( !hb_list_count( list ) )
4003         {
4004                 /* No valid title, stop right there */
4005                 g_message("No title found.\n");
4006                 return FALSE;
4007         }
4008
4009         gint titleindex;
4010
4011         titleindex = ghb_settings_combo_int(ud->settings, "title");
4012     title = hb_list_item( list, titleindex );
4013         if (title == NULL) return FALSE;
4014
4015         const GValue *slist, *settings;
4016         gint count, ii, source;
4017         gboolean burned, one_burned = FALSE;
4018
4019         slist = ghb_settings_get_value(ud->settings, "subtitle_list");
4020         count = ghb_array_len(slist);
4021         for (ii = 0; ii < count; ii++)
4022         {
4023                 settings = ghb_array_get_nth(slist, ii);
4024                 source = ghb_settings_get_int(settings, "SubtitleSource");
4025                 burned = ghb_settings_get_boolean(settings, "SubtitleBurned");
4026                 if (burned && one_burned)
4027                 {
4028                         // MP4 can only handle burned vobsubs.  make sure there isn't
4029                         // already something burned in the list
4030                         message = g_strdup_printf(
4031                         "Only one subtitle may be burned into the video.\n\n"
4032                                 "You should change your subtitle selections.\n"
4033                                 "If you continue, some subtitles will be lost.");
4034                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4035                         {
4036                                 g_free(message);
4037                                 return FALSE;
4038                         }
4039                         g_free(message);
4040                         break;
4041                 }
4042                 else if (burned)
4043                 {
4044                         one_burned = TRUE;
4045                 }
4046                 if (source == SRTSUB)
4047                 {
4048                         gchar *filename;
4049
4050                         filename = ghb_settings_get_string(settings, "SrtFile");
4051                         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
4052                         {
4053                                 message = g_strdup_printf(
4054                                 "Srt file does not exist or not a regular file.\n\n"
4055                                         "You should choose a valid file.\n"
4056                                         "If you continue, this subtitle will be ignored.");
4057                                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, 
4058                                         "Cancel", "Continue"))
4059                                 {
4060                                         g_free(message);
4061                                         return FALSE;
4062                                 }
4063                                 g_free(message);
4064                                 break;
4065                         }
4066                 }
4067         }
4068         return TRUE;
4069 }
4070
4071 gint
4072 ghb_select_audio_codec(GValue *settings, hb_audio_config_t *aconfig, gint acodec)
4073 {
4074         gint mux = ghb_settings_combo_int(settings, "FileFormat");
4075
4076         guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK;
4077         if (mux == HB_MUX_MP4)
4078         {
4079                 if ((acodec & in_codec & HB_ACODEC_AC3))
4080                 {
4081                         return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4082                 }
4083                 else if (acodec & HB_ACODEC_AC3)
4084                 {
4085                         return HB_ACODEC_AC3;
4086                 }
4087                 else if (acodec & HB_ACODEC_LAME)
4088                 {
4089                         return HB_ACODEC_LAME;
4090                 }
4091                 else if (acodec & HB_ACODEC_FAAC)
4092                 {
4093                         return HB_ACODEC_FAAC;
4094                 }
4095                 else
4096                 {
4097                         return HB_ACODEC_FAAC;
4098                 }
4099         }
4100         else
4101         {
4102                 if ((acodec & in_codec & HB_ACODEC_PASS_MASK))
4103                 {
4104                         return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4105                 }
4106                 else if (acodec & HB_ACODEC_AC3)
4107                 {
4108                         return HB_ACODEC_AC3;
4109                 }
4110                 else if (acodec & HB_ACODEC_VORBIS)
4111                 {
4112                         return HB_ACODEC_VORBIS;
4113                 }
4114                 else if (acodec & HB_ACODEC_LAME)
4115                 {
4116                         return HB_ACODEC_LAME;
4117                 }
4118                 else if (acodec & HB_ACODEC_FAAC)
4119                 {
4120                         return HB_ACODEC_FAAC;
4121                 }
4122                 else
4123                 {
4124                         return HB_ACODEC_LAME;
4125                 }
4126         }
4127 }
4128
4129 gboolean
4130 ghb_validate_audio(signal_user_data_t *ud)
4131 {
4132         hb_list_t  * list;
4133         hb_title_t * title;
4134         gchar *message;
4135         GValue *value;
4136
4137         if (h_scan == NULL) return FALSE;
4138         list = hb_get_titles( h_scan );
4139         if( !hb_list_count( list ) )
4140         {
4141                 /* No valid title, stop right there */
4142                 g_message("No title found.\n");
4143                 return FALSE;
4144         }
4145
4146         gint titleindex;
4147
4148         titleindex = ghb_settings_combo_int(ud->settings, "title");
4149     title = hb_list_item( list, titleindex );
4150         if (title == NULL) return FALSE;
4151         gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
4152
4153         const GValue *audio_list;
4154         gint count, ii;
4155
4156         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
4157         count = ghb_array_len(audio_list);
4158         for (ii = 0; ii < count; ii++)
4159         {
4160                 GValue *asettings;
4161             hb_audio_config_t *aconfig;
4162
4163                 asettings = ghb_array_get_nth(audio_list, ii);
4164                 gint track = ghb_settings_combo_int(asettings, "AudioTrack");
4165                 gint codec = ghb_settings_combo_int(asettings, "AudioEncoder");
4166                 if (codec == HB_ACODEC_ANY)
4167                         continue;
4168
4169         aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
4170                                                                                         title->list_audio, track );
4171                 if ( ghb_audio_is_passthru(codec) &&
4172                         !(ghb_audio_can_passthru(aconfig->in.codec) && 
4173                          (aconfig->in.codec & codec)))
4174                 {
4175                         // Not supported.  AC3 is passthrough only, so input must be AC3
4176                         message = g_strdup_printf(
4177                                                 "The source does not support Pass-Thru.\n\n"
4178                                                 "You should choose a different audio codec.\n"
4179                                                 "If you continue, one will be chosen for you.");
4180                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4181                         {
4182                                 g_free(message);
4183                                 return FALSE;
4184                         }
4185                         g_free(message);
4186                         if ((codec & HB_ACODEC_AC3) ||
4187                                 aconfig->in.codec == HB_ACODEC_DCA)
4188                         {
4189                                 codec = HB_ACODEC_AC3;
4190                         }
4191                         else if (mux == HB_MUX_MKV)
4192                         {
4193                                 codec = HB_ACODEC_LAME;
4194                         }
4195                         else
4196                         {
4197                                 codec = HB_ACODEC_FAAC;
4198                         }
4199                         value = ghb_lookup_acodec_value(codec);
4200                         ghb_settings_take_value(asettings, "AudioEncoder", value);
4201                 }
4202                 gchar *a_unsup = NULL;
4203                 gchar *mux_s = NULL;
4204                 if (mux == HB_MUX_MP4)
4205                 { 
4206                         mux_s = "MP4";
4207                         // mp4/vorbis|DTS combination is not supported.
4208                         if (codec == HB_ACODEC_VORBIS)
4209                         {
4210                                 a_unsup = "Vorbis";
4211                                 codec = HB_ACODEC_FAAC;
4212                         }
4213                         if (codec == HB_ACODEC_DCA)
4214                         {
4215                                 a_unsup = "DTS";
4216                                 codec = HB_ACODEC_AC3;
4217                         }
4218                 }
4219                 if (a_unsup)
4220                 {
4221                         message = g_strdup_printf(
4222                                                 "%s is not supported in the %s container.\n\n"
4223                                                 "You should choose a different audio codec.\n"
4224                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
4225                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4226                         {
4227                                 g_free(message);
4228                                 return FALSE;
4229                         }
4230                         g_free(message);
4231                         value = ghb_lookup_acodec_value(codec);
4232                         ghb_settings_take_value(asettings, "AudioEncoder", value);
4233                 }
4234
4235                 gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
4236                 gboolean allow_mono = TRUE;
4237                 gboolean allow_stereo = TRUE;
4238                 gboolean allow_dolby = TRUE;
4239                 gboolean allow_dpl2 = TRUE;
4240                 gboolean allow_6ch = TRUE;
4241                 allow_mono = TRUE;
4242
4243                 gint best = hb_get_best_mixdown(codec, aconfig->in.channel_layout, 0);
4244
4245                 allow_stereo = best >= HB_AMIXDOWN_STEREO;
4246                 allow_dolby = best >= HB_AMIXDOWN_DOLBY;
4247                 allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
4248                 allow_6ch = best >= HB_AMIXDOWN_6CH;
4249
4250                 gchar *mix_unsup = NULL;
4251                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
4252                 {
4253                         mix_unsup = "mono";
4254                 }
4255                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
4256                 {
4257                         mix_unsup = "stereo";
4258                 }
4259                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
4260                 {
4261                         mix_unsup = "Dolby";
4262                 }
4263                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
4264                 {
4265                         mix_unsup = "Dolby Pro Logic II";
4266                 }
4267                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
4268                 {
4269                         mix_unsup = "6 Channel";
4270                 }
4271                 if (mix_unsup)
4272                 {
4273                         message = g_strdup_printf(
4274                                                 "The source audio does not support %s mixdown.\n\n"
4275                                                 "You should choose a different mixdown.\n"
4276                                                 "If you continue, one will be chosen for you.", mix_unsup);
4277                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4278                         {
4279                                 g_free(message);
4280                                 return FALSE;
4281                         }
4282                         g_free(message);
4283                         mix = ghb_get_best_mix(aconfig, codec, mix);
4284                         value = get_amix_value(mix);
4285                         ghb_settings_take_value(asettings, "AudioMixdown", value);
4286                 }
4287         }
4288         return TRUE;
4289 }
4290
4291 gboolean
4292 ghb_validate_vquality(GValue *settings)
4293 {
4294         gint vcodec;
4295         gchar *message;
4296         gint min, max;
4297
4298         if (ghb_settings_get_boolean(settings, "nocheckvquality")) return TRUE;
4299         vcodec = ghb_settings_combo_int(settings, "VideoEncoder");
4300         gdouble vquality;
4301         vquality = ghb_settings_get_double(settings, "VideoQualitySlider");
4302         if (ghb_settings_get_boolean(settings, "vquality_type_constant"))
4303         {
4304                 switch (vcodec)
4305                 {
4306                         case HB_VCODEC_X264:
4307                         {
4308                                 min = 16;
4309                                 max = 30;
4310                         } break;
4311
4312                         case HB_VCODEC_FFMPEG:
4313                         {
4314                                 min = 1;
4315                                 max = 8;
4316                         } break;
4317
4318                         case HB_VCODEC_THEORA:
4319                         {
4320                                 min = 0;
4321                                 max = 63;
4322                         } break;
4323
4324                         default:
4325                         {
4326                                 min = 48;
4327                                 max = 62;
4328                         } break;
4329                 }
4330                 if (vcodec == HB_VCODEC_X264 && vquality == 0.0)
4331                 {
4332                         message = g_strdup_printf(
4333                                                 "Warning: lossless h.264 selected\n\n"
4334                                                 "Lossless h.264 is not well supported by\n"
4335                                                 "many players and editors.\n\n"
4336                         "It will produce enormous output files.\n\n"
4337                                                 "Are you sure you wish to use this setting?",
4338                                                 (gint)vquality, min, max);
4339                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
4340                                                                         "Cancel", "Continue"))
4341                         {
4342                                 g_free(message);
4343                                 return FALSE;
4344                         }
4345                         g_free(message);
4346                 }
4347                 else if (vquality < min || vquality > max)
4348                 {
4349                         message = g_strdup_printf(
4350                                                 "Interesting video quality choice: %d\n\n"
4351                                                 "Typical values range from %d to %d.\n\n"
4352                                                 "Are you sure you wish to use this setting?",
4353                                                 (gint)vquality, min, max);
4354                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
4355                                                                         "Cancel", "Continue"))
4356                         {
4357                                 g_free(message);
4358                                 return FALSE;
4359                         }
4360                         g_free(message);
4361                 }
4362         }
4363         return TRUE;
4364 }
4365
4366 static void
4367 add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
4368 {
4369         hb_list_t  * list;
4370         hb_title_t * title;
4371         hb_job_t   * job;
4372         static gchar *x264opts;
4373         gint sub_id = 0;
4374         gboolean tweaks = FALSE;
4375         gchar *detel_str = NULL;
4376         gchar *decomb_str = NULL;
4377         gchar *deint_str = NULL;
4378         gchar *deblock_str = NULL;
4379         gchar *denoise_str = NULL;
4380         gchar *dest_str = NULL;
4381
4382         g_debug("add_job()\n");
4383         if (h == NULL) return;
4384         list = hb_get_titles( h );
4385         if( !hb_list_count( list ) )
4386         {
4387                 /* No valid title, stop right there */
4388                 return;
4389         }
4390
4391     title = hb_list_item( list, titleindex );
4392         if (title == NULL) return;
4393
4394         /* Set job settings */
4395         job   = title->job;
4396         if (job == NULL) return;
4397
4398         job->angle = ghb_settings_get_int(js, "angle");
4399         job->start_at_preview = ghb_settings_get_int(js, "start_frame") + 1;
4400         if (job->start_at_preview)
4401         {
4402                 job->seek_points = ghb_settings_get_int(js, "preview_count");
4403                 job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL;
4404         }
4405
4406         tweaks = ghb_settings_get_boolean(js, "allow_tweaks");
4407         job->mux = ghb_settings_combo_int(js, "FileFormat");
4408         if (job->mux == HB_MUX_MP4)
4409         {
4410                 job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile");
4411                 job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize");
4412         }
4413         else
4414         {
4415                 job->largeFileSize = FALSE;
4416                 job->mp4_optimize = FALSE;
4417         }
4418         if (!job->start_at_preview)
4419         {
4420                 gint start, end;
4421                 gint num_chapters = hb_list_count(title->list_chapter);
4422                 gint duration = title->duration / 90000;
4423                 job->chapter_markers = FALSE;
4424                 job->chapter_start = 1;
4425                 job->chapter_end = num_chapters;
4426
4427                 if (ghb_settings_combo_int(js, "PtoPType") == 0)
4428                 {
4429                         start = ghb_settings_get_int(js, "start_point");
4430                         end = ghb_settings_get_int(js, "end_point");
4431                         job->chapter_start = MIN( num_chapters, start );
4432                         job->chapter_end   = MAX( job->chapter_start, end );
4433
4434                 }
4435                 if (ghb_settings_combo_int(js, "PtoPType") == 1)
4436                 {
4437                         start = ghb_settings_get_int(js, "start_point");
4438                         end = ghb_settings_get_int(js, "end_point");
4439                         job->pts_to_start = (int64_t)MIN(duration-1, start) * 90000;
4440                         job->pts_to_stop = (int64_t)MAX(start+1, end) * 90000 - 
4441                                                                 job->pts_to_start;
4442                 }
4443                 if (ghb_settings_combo_int(js, "PtoPType") == 2)
4444                 {
4445                         start = ghb_settings_get_int(js, "start_point");
4446                         end = ghb_settings_get_int(js, "end_point");
4447                         gint64 max_frames;
4448                         max_frames = (gint64)duration * title->rate / title->rate_base;
4449                         job->frame_to_start = (int64_t)MIN(max_frames-1, start-1);
4450                         job->frame_to_stop = (int64_t)MAX(start, end-1) - 
4451                                                                  job->frame_to_start;
4452                 }
4453                 if (job->chapter_start != job->chapter_end)
4454                 {
4455                         job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
4456                 }
4457                 if (job->chapter_start == job->chapter_end)
4458                         job->chapter_markers = 0;
4459                 if ( job->chapter_markers )
4460                 {
4461                         GValue *chapters;
4462                         GValue *chapter;
4463                         gint chap;
4464                         gint count;
4465
4466                         chapters = ghb_settings_get_value(js, "chapter_list");
4467                         count = ghb_array_len(chapters);
4468                         for(chap = 0; chap < count; chap++)
4469                         {
4470                                 hb_chapter_t * chapter_s;
4471                                 gchar *name;
4472
4473                                 name = NULL;
4474                                 chapter = ghb_array_get_nth(chapters, chap);
4475                                 name = ghb_value_string(chapter); 
4476                                 if (name == NULL)
4477                                 {
4478                                         name = g_strdup_printf ("Chapter %2d", chap+1);
4479                                 }
4480                                 chapter_s = hb_list_item( job->title->list_chapter, chap);
4481                                 strncpy(chapter_s->title, name, 1023);
4482                                 chapter_s->title[1023] = '\0';
4483                                 g_free(name);
4484                         }
4485                 }
4486         }
4487         job->crop[0] = ghb_settings_get_int(js, "PictureTopCrop");
4488         job->crop[1] = ghb_settings_get_int(js, "PictureBottomCrop");
4489         job->crop[2] = ghb_settings_get_int(js, "PictureLeftCrop");
4490         job->crop[3] = ghb_settings_get_int(js, "PictureRightCrop");
4491
4492         
4493         gboolean decomb_deint = ghb_settings_get_boolean(js, "PictureDecombDeinterlace");
4494         gint decomb = ghb_settings_combo_int(js, "PictureDecomb");
4495         gint deint = ghb_settings_combo_int(js, "PictureDeinterlace");
4496         if (!decomb_deint)
4497                 job->deinterlace = (deint != 0) ? 1 : 0;
4498         else
4499                 job->deinterlace = 0;
4500     job->grayscale   = ghb_settings_get_boolean(js, "VideoGrayScale");
4501
4502         gboolean keep_aspect;
4503         keep_aspect = ghb_settings_get_boolean(js, "PictureKeepRatio");
4504         job->anamorphic.mode = ghb_settings_combo_int(js, "PicturePAR");
4505         job->modulus = ghb_settings_combo_int(js, "PictureModulus");
4506         if (job->anamorphic.mode)
4507         {
4508                 job->anamorphic.par_width = title->pixel_aspect_width;
4509                 job->anamorphic.par_height = title->pixel_aspect_height;
4510                 job->anamorphic.dar_width = 0;
4511                 job->anamorphic.dar_height = 0;
4512
4513                 if (job->anamorphic.mode == 3 && !keep_aspect)
4514                 {
4515                         job->anamorphic.keep_display_aspect = 0;
4516                         job->anamorphic.par_width = 
4517                                 ghb_settings_get_int(js, "PicturePARWidth");
4518                         job->anamorphic.par_height = 
4519                                 ghb_settings_get_int(js, "PicturePARHeight");
4520                 }
4521                 else
4522                 {
4523                         job->anamorphic.keep_display_aspect = 1;
4524                 }
4525         }
4526
4527         /* Add selected filters */
4528         job->filters = hb_list_init();
4529         gint detel = ghb_settings_combo_int(js, "PictureDetelecine");
4530         if ( detel )
4531         {
4532                 if (detel != 1)
4533                 {
4534                         if (detel_opts.map[detel].svalue != NULL)
4535                                 detel_str = g_strdup(detel_opts.map[detel].svalue);
4536                 }
4537                 else
4538                         detel_str = ghb_settings_get_string(js, "PictureDetelecineCustom");
4539                 hb_filter_detelecine.settings = detel_str;
4540                 hb_list_add( job->filters, &hb_filter_detelecine );
4541         }
4542         if ( decomb_deint && decomb )
4543         {
4544                 if (decomb != 1)
4545                 {
4546                         if (decomb_opts.map[decomb].svalue != NULL)
4547                                 decomb_str = g_strdup(decomb_opts.map[decomb].svalue);
4548                 }
4549                 else
4550                         decomb_str = ghb_settings_get_string(js, "PictureDecombCustom");
4551                 hb_filter_decomb.settings = decomb_str;
4552                 hb_list_add( job->filters, &hb_filter_decomb );
4553         }
4554         if( job->deinterlace )
4555         {
4556                 if (deint != 1)
4557                 {
4558                         if (deint_opts.map[deint].svalue != NULL)
4559                                 deint_str = g_strdup(deint_opts.map[deint].svalue);
4560                 }
4561                 else
4562                         deint_str = ghb_settings_get_string(js, "PictureDeinterlaceCustom");
4563                 hb_filter_deinterlace.settings = deint_str;
4564                 hb_list_add( job->filters, &hb_filter_deinterlace );
4565         }
4566         gint deblock = ghb_settings_get_int(js, "PictureDeblock");
4567         if( deblock >= 5 )
4568         {
4569                 deblock_str = g_strdup_printf("%d", deblock);
4570                 hb_filter_deblock.settings = deblock_str;
4571                 hb_list_add( job->filters, &hb_filter_deblock );
4572         }
4573         gint denoise = ghb_settings_combo_int(js, "PictureDenoise");
4574         if( denoise )
4575         {
4576                 if (denoise != 1)
4577                 {
4578                         if (denoise_opts.map[denoise].svalue != NULL)
4579                                 denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
4580                 }
4581                 else
4582                         denoise_str = ghb_settings_get_string(js, "PictureDenoiseCustom");
4583                 hb_filter_denoise.settings = denoise_str;
4584                 hb_list_add( job->filters, &hb_filter_denoise );
4585         }
4586         job->width = ghb_settings_get_int(js, "scale_width");
4587         job->height = ghb_settings_get_int(js, "scale_height");
4588
4589         job->vcodec = ghb_settings_combo_int(js, "VideoEncoder");
4590         if ((job->mux == HB_MUX_MP4 ) && (job->vcodec == HB_VCODEC_THEORA))
4591         {
4592                 // mp4/theora combination is not supported.
4593                 job->vcodec = HB_VCODEC_FFMPEG;
4594         }
4595         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
4596         {
4597                 job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible");
4598         }
4599         if (ghb_settings_get_boolean(js, "vquality_type_constant"))
4600         {
4601                 gdouble vquality;
4602                 vquality = ghb_settings_get_double(js, "VideoQualitySlider");
4603                 job->vquality =  vquality;
4604                 job->vbitrate = 0;
4605         }
4606         else if (ghb_settings_get_boolean(js, "vquality_type_bitrate"))
4607         {
4608                 job->vquality = -1.0;
4609                 job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
4610         }
4611
4612         gint vrate = ghb_settings_combo_int(js, "VideoFramerate");
4613         if( vrate == 0 )
4614         {
4615                 job->vrate = title->rate;
4616                 job->vrate_base = title->rate_base;
4617         }
4618         else
4619         {
4620                 job->vrate = 27000000;
4621                 job->vrate_base = vrate;
4622         }
4623         if (ghb_settings_get_boolean(js, "VideoFrameratePFR"))
4624                 job->cfr = 2;
4625         else if (ghb_settings_get_boolean(js, "VideoFramerateCFR"))
4626                 job->cfr = 1;
4627         else
4628                 job->cfr = 0;
4629
4630         const GValue *audio_list;
4631         gint count, ii;
4632         gint tcount = 0;
4633         
4634         audio_list = ghb_settings_get_value(js, "audio_list");
4635         count = ghb_array_len(audio_list);
4636         for (ii = 0; ii < count; ii++)
4637         {
4638                 GValue *asettings;
4639             hb_audio_config_t audio;
4640             hb_audio_config_t *aconfig;
4641                 gint acodec;
4642
4643                 hb_audio_config_init(&audio);
4644                 asettings = ghb_array_get_nth(audio_list, ii);
4645                 audio.in.track = ghb_settings_get_int(asettings, "AudioTrack");
4646                 audio.out.track = tcount;
4647
4648         aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
4649                                                                         title->list_audio, audio.in.track );
4650
4651                 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
4652                 audio.out.codec = ghb_select_audio_codec(js, aconfig, acodec);
4653
4654         audio.out.dynamic_range_compression = 
4655                         ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
4656         if (audio.out.dynamic_range_compression < 1.0)
4657                 audio.out.dynamic_range_compression = 0.0;
4658
4659                 // It would be better if this were done in libhb for us, but its not yet.
4660                 if (ghb_audio_is_passthru(audio.out.codec))
4661                 {
4662                         audio.out.mixdown = 0;
4663                 }
4664                 else
4665                 {
4666                         audio.out.mixdown = ghb_settings_combo_int(asettings, "AudioMixdown");
4667                         // Make sure the mixdown is valid and pick a new one if not.
4668                         audio.out.mixdown = ghb_get_best_mix(aconfig, audio.out.codec, 
4669                                                                                                         audio.out.mixdown);
4670                         audio.out.bitrate = 
4671                                 ghb_settings_combo_int(asettings, "AudioBitrate");
4672                         gint srate = ghb_settings_combo_int(asettings, "AudioSamplerate");
4673                         if (srate == 0) // 0 is same as source
4674                                 audio.out.samplerate = aconfig->in.samplerate;
4675                         else
4676                                 audio.out.samplerate = srate;
4677
4678                         audio.out.bitrate = hb_get_best_audio_bitrate(
4679                                 audio.out.codec, audio.out.bitrate, 
4680                                 audio.out.samplerate, audio.out.mixdown);
4681                 }
4682
4683                 // Add it to the jobs audio list
4684         hb_audio_add( job, &audio );
4685                 tcount++;
4686         }
4687
4688         dest_str = ghb_settings_get_string(js, "destination");
4689         job->file = dest_str;
4690
4691         const GValue *subtitle_list;
4692         gint subtitle;
4693         gboolean force, burned, def, one_burned = FALSE;
4694         
4695         ghb_settings_set_boolean(js, "subtitle_scan", FALSE);
4696         subtitle_list = ghb_settings_get_value(js, "subtitle_list");
4697         count = ghb_array_len(subtitle_list);
4698         for (ii = 0; ii < count; ii++)
4699         {
4700                 GValue *ssettings;
4701                 gint source;
4702
4703                 ssettings = ghb_array_get_nth(subtitle_list, ii);
4704
4705                 force = ghb_settings_get_boolean(ssettings, "SubtitleForced");
4706                 burned = ghb_settings_get_boolean(ssettings, "SubtitleBurned");
4707                 def = ghb_settings_get_boolean(ssettings, "SubtitleDefaultTrack");
4708                 source = ghb_settings_get_int(ssettings, "SubtitleSource");
4709
4710                 if (source == SRTSUB)
4711                 {
4712                 hb_subtitle_config_t sub_config;
4713                         gchar *filename, *lang, *code;
4714
4715                         filename = ghb_settings_get_string(ssettings, "SrtFile");
4716                         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
4717                         {
4718                                 continue;
4719                         }
4720                         sub_config.offset = ghb_settings_get_int(ssettings, "SrtOffset");
4721                         lang = ghb_settings_get_string(ssettings, "SrtLanguage");
4722                         code = ghb_settings_get_string(ssettings, "SrtCodeset");
4723                         strncpy(sub_config.src_filename, filename, 255);
4724                         sub_config.src_filename[255] = 0;
4725                         strncpy(sub_config.src_codeset, code, 39);
4726                         sub_config.src_codeset[39] = 0;
4727                         sub_config.force = 0;
4728                         sub_config.dest = PASSTHRUSUB;
4729                         sub_config.default_track = def;
4730
4731                         hb_srt_add( job, &sub_config, lang);
4732
4733                         g_free(filename);
4734                         g_free(lang);
4735                         g_free(code);
4736                         continue;
4737                 }
4738
4739                 subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack");
4740                 if (subtitle == -1)
4741                 {
4742                         if (!burned)
4743                         {
4744                                 job->select_subtitle_config.dest = PASSTHRUSUB;
4745                         }
4746                         else if (burned)
4747                         {
4748                                 // Only allow one subtitle to be burned into the video
4749                                 if (one_burned)
4750                                         continue;
4751                                 job->select_subtitle_config.dest = RENDERSUB;
4752                                 one_burned = TRUE;
4753                         }
4754                         job->select_subtitle_config.force = force;
4755                         job->select_subtitle_config.default_track = def;
4756                         job->indepth_scan = 1;
4757                         ghb_settings_set_boolean(js, "subtitle_scan", TRUE);
4758                 }
4759                 else if (subtitle >= 0)
4760                 {
4761                 hb_subtitle_t * subt;
4762                 hb_subtitle_config_t sub_config;
4763
4764                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
4765                         if (subt != NULL)
4766                         {
4767                                 sub_config = subt->config;
4768                                 if (!burned)
4769                                 {
4770                                         sub_config.dest = PASSTHRUSUB;
4771                                 }
4772                                 else if ( burned && canBurn(subt->source) )
4773                                 {
4774                                         // Only allow one subtitle to be burned into the video
4775                                         if (one_burned)
4776                                                 continue;
4777                                         sub_config.dest = RENDERSUB;
4778                                         one_burned = TRUE;
4779                                 }
4780                                 sub_config.force = force;
4781                                 sub_config.default_track = def;
4782                         hb_subtitle_add( job, &sub_config, subtitle );
4783                         }
4784                 }
4785         }
4786
4787         // TODO: libhb holds onto a reference to the x264opts and is not
4788         // finished with it until encoding the job is done.  But I can't
4789         // find a way to get at the job before it is removed in order to
4790         // free up the memory I am allocating here.
4791         // The short story is THIS LEAKS.
4792         x264opts = ghb_build_x264opts_string(js);
4793         
4794         if( *x264opts == '\0' )
4795         {
4796                 g_free(x264opts);
4797                 x264opts = NULL;
4798         }
4799
4800         if (job->indepth_scan == 1)
4801         {
4802                 // Subtitle scan. Look for subtitle matching audio language
4803
4804                 /*
4805                  * When subtitle scan is enabled do a fast pre-scan job
4806                  * which will determine which subtitles to enable, if any.
4807                  */
4808                 job->pass = -1;
4809                 job->indepth_scan = 1;
4810                 job->x264opts = NULL;
4811
4812                 /*
4813                  * Add the pre-scan job
4814                  */
4815                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4816                 hb_add( h, job );
4817         }
4818
4819         if( ghb_settings_get_boolean(js, "VideoTwoPass") &&
4820                 !ghb_settings_get_boolean(js, "vquality_type_constant"))
4821         {
4822                 /*
4823                  * If subtitle_scan is enabled then only turn it on
4824                  * for the second pass and then off again for the
4825                  * second.
4826                  */
4827                 job->pass = 1;
4828                 job->indepth_scan = 0;
4829
4830                 /*
4831                  * If turbo options have been selected then append them
4832                  * to the x264opts now (size includes one ':' and the '\0')
4833                  */
4834                 if( ghb_settings_get_boolean(js, "VideoTurboTwoPass") )
4835                 {
4836                         gchar *tmp_x264opts;
4837                         gchar *extra_opts;
4838                         gint badapt;
4839
4840                         badapt = ghb_lookup_badapt(x264opts);
4841                         if (badapt == 2)
4842                         {
4843                                 extra_opts = g_strdup_printf("%s", turbo_opts);
4844                         }
4845                         else
4846                         {
4847                                 extra_opts = g_strdup_printf("%s:weightb=0", turbo_opts);
4848                         }
4849         
4850                         if ( x264opts )
4851                         {
4852                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, extra_opts);
4853                         } 
4854                         else 
4855                         {
4856                                 /*
4857                                  * No x264opts to modify, but apply the turbo options
4858                                  * anyway as they may be modifying defaults
4859                                  */
4860                                 tmp_x264opts = g_strdup_printf("%s", extra_opts);
4861                         }
4862                         g_free(extra_opts);
4863
4864                         job->x264opts = tmp_x264opts;
4865                 }
4866                 else
4867                 {
4868                         job->x264opts = x264opts;
4869                 }
4870                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4871                 hb_add( h, job );
4872                 //if (job->x264opts != NULL)
4873                 //      g_free(job->x264opts);
4874
4875                 job->pass = 2;
4876                 /*
4877                  * On the second pass we turn off subtitle scan so that we
4878                  * can actually encode using any subtitles that were auto
4879                  * selected in the first pass (using the whacky select-subtitle
4880                  * attribute of the job).
4881                  */
4882                 job->indepth_scan = 0;
4883                 job->x264opts = x264opts;
4884                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4885                 hb_add( h, job );
4886                 //if (job->x264opts != NULL)
4887                 //      g_free(job->x264opts);
4888         }
4889         else
4890         {
4891                 job->x264opts = x264opts;
4892                 job->indepth_scan = 0;
4893                 job->pass = 0;
4894                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4895                 hb_add( h, job );
4896                 //if (job->x264opts != NULL)
4897                 //      g_free(job->x264opts);
4898         }
4899
4900         // clean up audio list
4901         gint num_audio_tracks = hb_list_count(job->list_audio);
4902         for(ii = 0; ii < num_audio_tracks; ii++)
4903         {
4904                 hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
4905                 hb_list_rem(job->list_audio, audio);
4906                 free(audio);
4907         }
4908
4909         // clean up subtitle list
4910         gint num_subtitle_tracks = hb_list_count(job->list_subtitle);
4911         for(ii = 0; ii < num_subtitle_tracks; ii++)
4912         {
4913                 hb_subtitle_t *subtitle = hb_list_item(job->list_subtitle, 0);
4914                 hb_list_rem(job->list_subtitle, subtitle);
4915                 free(subtitle);
4916         }
4917
4918         if (detel_str) g_free(detel_str);
4919         if (decomb_str) g_free(decomb_str);
4920         if (deint_str) g_free(deint_str);
4921         if (deblock_str) g_free(deblock_str);
4922         if (denoise_str) g_free(denoise_str);
4923         if (dest_str) g_free(dest_str);
4924 }
4925
4926 void
4927 ghb_add_job(GValue *js, gint unique_id)
4928 {
4929         // Since I'm doing a scan of the single title I want just prior 
4930         // to adding the job, there is only the one title to choose from.
4931         add_job(h_queue, js, unique_id, 0);
4932 }
4933
4934 void
4935 ghb_add_live_job(GValue *js, gint unique_id)
4936 {
4937         // Since I'm doing a scan of the single title I want just prior 
4938         // to adding the job, there is only the one title to choose from.
4939         gint titleindex = ghb_settings_combo_int(js, "title");
4940         add_job(h_scan, js, unique_id, titleindex);
4941 }
4942
4943 void
4944 ghb_remove_job(gint unique_id)
4945 {
4946     hb_job_t * job;
4947     gint ii;
4948         
4949         // Multiples passes all get the same id
4950         // remove them all.
4951         // Go backwards through list, so reordering doesn't screw me.
4952         ii = hb_count(h_queue) - 1;
4953     while ((job = hb_job(h_queue, ii--)) != NULL)
4954     {
4955         if ((job->sequence_id & 0xFFFFFF) == unique_id)
4956                         hb_rem(h_queue, job);
4957     }
4958 }
4959
4960 void
4961 ghb_start_queue()
4962 {
4963         hb_start( h_queue );
4964 }
4965
4966 void
4967 ghb_stop_queue()
4968 {
4969         hb_stop( h_queue );
4970 }
4971
4972 void
4973 ghb_start_live_encode()
4974 {
4975         hb_start( h_scan );
4976 }
4977
4978 void
4979 ghb_stop_live_encode()
4980 {
4981         hb_stop( h_scan );
4982 }
4983
4984 void
4985 ghb_pause_queue()
4986 {
4987     hb_state_t s;
4988     hb_get_state2( h_queue, &s );
4989
4990     if( s.state == HB_STATE_PAUSED )
4991     {
4992                 hb_status.queue.state &= ~GHB_STATE_PAUSED;
4993                 hb_resume( h_queue );
4994     }
4995     else
4996     {
4997                 hb_status.queue.state |= GHB_STATE_PAUSED;
4998                 hb_pause( h_queue );
4999     }
5000 }
5001
5002 static void
5003 vert_line(
5004         GdkPixbuf * pb, 
5005         guint8 r, 
5006         guint8 g, 
5007         guint8 b, 
5008         gint x, 
5009         gint y, 
5010         gint len, 
5011         gint width)
5012 {
5013         guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5014         guint8 *dst;
5015         gint ii, jj;
5016         gint channels = gdk_pixbuf_get_n_channels (pb);
5017         gint stride = gdk_pixbuf_get_rowstride (pb);
5018
5019         for (jj = 0; jj < width; jj++)
5020         {
5021                 dst = pixels + y * stride + (x+jj) * channels;
5022                 for (ii = 0; ii < len; ii++)
5023                 {
5024                         dst[0] = r;
5025                         dst[1] = g;
5026                         dst[2] = b;
5027                         dst += stride;
5028                 }
5029         }
5030 }
5031
5032 static void
5033 horz_line(
5034         GdkPixbuf * pb, 
5035         guint8 r, 
5036         guint8 g, 
5037         guint8 b, 
5038         gint x, 
5039         gint y, 
5040         gint len,
5041         gint width)
5042 {
5043         guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5044         guint8 *dst;
5045         gint ii, jj;
5046         gint channels = gdk_pixbuf_get_n_channels (pb);
5047         gint stride = gdk_pixbuf_get_rowstride (pb);
5048
5049         for (jj = 0; jj < width; jj++)
5050         {
5051                 dst = pixels + (y+jj) * stride + x * channels;
5052                 for (ii = 0; ii < len; ii++)
5053                 {
5054                         dst[0] = r;
5055                         dst[1] = g;
5056                         dst[2] = b;
5057                         dst += channels;
5058                 }
5059         }
5060 }
5061
5062 static void
5063 hash_pixbuf(
5064         GdkPixbuf * pb,
5065         gint        x,
5066         gint        y,
5067         gint        w,
5068         gint        h,
5069         gint        step,
5070         gint            orientation)
5071 {
5072         gint ii, jj;
5073         gint line_width = 8;
5074         struct
5075         {
5076                 guint8 r;
5077                 guint8 g;
5078                 guint8 b;
5079         } c[4] = 
5080         {{0x80, 0x80, 0x80},{0xC0, 0x80, 0x70},{0x80, 0xA0, 0x80},{0x70, 0x80, 0xA0}};
5081
5082         if (!orientation)
5083         {
5084                 // vertical lines
5085                 for (ii = x, jj = 0; ii+line_width < x+w; ii += step, jj++)
5086                 {
5087                         vert_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, ii, y, h, line_width);
5088                 }
5089         }
5090         else
5091         {
5092                 // horizontal lines
5093                 for (ii = y, jj = 0; ii+line_width < y+h; ii += step, jj++)
5094                 {
5095                         horz_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, x, ii, w, line_width);
5096                 }
5097         }
5098 }
5099
5100 GdkPixbuf*
5101 ghb_get_preview_image(
5102         gint titleindex, 
5103         gint index, 
5104         signal_user_data_t *ud,
5105         gint *out_width,
5106         gint *out_height)
5107 {
5108         GValue *settings;
5109         hb_title_t *title;
5110         hb_list_t  *list;
5111         
5112         settings = ud->settings;
5113         list = hb_get_titles( h_scan );
5114         if( !hb_list_count( list ) )
5115         {
5116                 /* No valid title, stop right there */
5117                 return NULL;
5118         }
5119     title = hb_list_item( list, titleindex );
5120         if (title == NULL) return NULL;
5121         if (title->job == NULL) return NULL;
5122         set_preview_job_settings(title->job, settings);
5123
5124         // hb_get_preview doesn't compensate for anamorphic, so lets
5125         // calculate scale factors
5126         gint width, height, par_width = 1, par_height = 1;
5127         gint pic_par = ghb_settings_combo_int(settings, "PicturePAR");
5128         if (pic_par)
5129         {
5130                 hb_set_anamorphic_size( title->job, &width, &height, 
5131                                                                 &par_width, &par_height );
5132         }
5133
5134         // Make sure we have a big enough buffer to receive the image from libhb
5135         gint dstWidth = title->job->width;
5136         gint dstHeight= title->job->height;
5137
5138         static guint8 *buffer = NULL;
5139         static gint bufferSize = 0;
5140         gint newSize;
5141
5142         newSize = dstWidth * dstHeight * 4;
5143         if( bufferSize < newSize )
5144         {
5145                 bufferSize = newSize;
5146                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
5147         }
5148         hb_get_preview( h_scan, title, index, buffer );
5149
5150         // Create an GdkPixbuf and copy the libhb image into it, converting it from
5151         // libhb's format something suitable.
5152         
5153         // The image data returned by hb_get_preview is 4 bytes per pixel, 
5154         // BGRA format. Alpha is ignored.
5155
5156         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
5157         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
5158         
5159         guint32 *src = (guint32*)buffer;
5160         guint8 *dst = pixels;
5161
5162         gint ii, jj;
5163         gint channels = gdk_pixbuf_get_n_channels (preview);
5164         gint stride = gdk_pixbuf_get_rowstride (preview);
5165         guint8 *tmp;
5166
5167         for (ii = 0; ii < dstHeight; ii++)
5168         {
5169                 tmp = dst;
5170                 for (jj = 0; jj < dstWidth; jj++)
5171                 {
5172                         tmp[0] = src[0] >> 16;
5173                         tmp[1] = src[0] >> 8;
5174                         tmp[2] = src[0] >> 0;
5175                         tmp += channels;
5176                         src++;
5177                 }
5178                 dst += stride;
5179         }
5180         gint w = ghb_settings_get_int(settings, "scale_width");
5181         gint h = ghb_settings_get_int(settings, "scale_height");
5182         ghb_par_scale(ud, &w, &h, par_width, par_height);
5183
5184         gint c0, c1, c2, c3;
5185         c0 = ghb_settings_get_int(settings, "PictureTopCrop");
5186         c1 = ghb_settings_get_int(settings, "PictureBottomCrop");
5187         c2 = ghb_settings_get_int(settings, "PictureLeftCrop");
5188         c3 = ghb_settings_get_int(settings, "PictureRightCrop");
5189
5190         gdouble xscale = (gdouble)w / (gdouble)(title->width - c2 - c3);
5191         gdouble yscale = (gdouble)h / (gdouble)(title->height - c0 - c1);
5192         
5193         ghb_par_scale(ud, &dstWidth, &dstHeight, par_width, par_height);
5194         *out_width = w;
5195         *out_height = h;
5196         if (ghb_settings_get_boolean(settings, "reduce_hd_preview"))
5197         {
5198                 GdkScreen *ss;
5199                 gint s_w, s_h;
5200                 gint orig_w, orig_h;
5201                 gint factor = 80;
5202
5203                 if (ghb_settings_get_boolean(settings, "preview_fullscreen"))
5204                 {
5205                         factor = 100;
5206                 }
5207                 ss = gdk_screen_get_default();
5208                 s_w = gdk_screen_get_width(ss);
5209                 s_h = gdk_screen_get_height(ss);
5210                 orig_w = dstWidth;
5211                 orig_h = dstHeight;
5212
5213                 if (dstWidth > s_w * factor / 100)
5214                 {
5215                         dstWidth = s_w * factor / 100;
5216                         dstHeight = dstHeight * dstWidth / orig_w;
5217                 }
5218                 if (dstHeight > s_h * factor / 100)
5219                 {
5220                         dstHeight = s_h * factor / 100;
5221                         dstWidth = dstWidth * dstHeight / orig_h;
5222                 }
5223                 xscale *= (gdouble)dstWidth / orig_w;
5224                 yscale *= (gdouble)dstHeight / orig_h;
5225                 w *= (gdouble)dstWidth / orig_w;
5226                 h *= (gdouble)dstHeight / orig_h;
5227         }
5228         GdkPixbuf *scaled_preview;
5229         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
5230         if (ghb_settings_get_boolean(settings, "show_crop"))
5231         {
5232                 c0 *= yscale;
5233                 c1 *= yscale;
5234                 c2 *= xscale;
5235                 c3 *= xscale;
5236                 // Top
5237                 hash_pixbuf(scaled_preview, c2, 0, w, c0, 32, 0);
5238                 // Bottom
5239                 hash_pixbuf(scaled_preview, c2, dstHeight-c1, w, c1, 32, 0);
5240                 // Left
5241                 hash_pixbuf(scaled_preview, 0, c0, c2, h, 32, 1);
5242                 // Right
5243                 hash_pixbuf(scaled_preview, dstWidth-c3, c0, c3, h, 32, 1);
5244         }
5245         g_object_unref (preview);
5246         return scaled_preview;
5247 }
5248
5249 static void
5250 sanitize_volname(gchar *name)
5251 {
5252         gchar *a, *b;
5253
5254         a = b = name;
5255         while (*b)
5256         {
5257                 switch(*b)
5258                 {
5259                 case '<':
5260                         b++;
5261                         break;
5262                 case '>':
5263                         b++;
5264                         break;
5265                 default:
5266                         *a = *b;
5267                         a++; b++;
5268                         break;
5269                 }
5270         }
5271         *a = 0;
5272 }
5273
5274 gchar*
5275 ghb_dvd_volname(const gchar *device)
5276 {
5277         gchar *name;
5278         name = hb_dvd_name((gchar*)device);
5279         if (name != NULL && name[0] != 0)
5280         {
5281                 name = g_strdup(name);
5282                 sanitize_volname(name);
5283                 return name;
5284         }
5285         return NULL;
5286 }