OSDN Git Service

c73d63dfeefedcf3e58d17e601c616eb97a49109
[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 gint
3860 ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
3861 {
3862         hb_list_t  * list;
3863         hb_title_t * title;
3864         hb_job_t   * job;
3865         gint size;
3866
3867         if (h_scan == NULL) return 1500;
3868         list = hb_get_titles( h_scan );
3869     title = hb_list_item( list, titleindex );
3870         if (title == NULL) return 1500;
3871         job   = title->job;
3872         if (job == NULL) return 1500;
3873         size = ghb_settings_get_int(settings, "VideoTargetSize");
3874         return hb_calc_bitrate( job, size );
3875 }
3876
3877 gboolean
3878 ghb_validate_filter_string(const gchar *str, gint max_fields)
3879 {
3880         gint fields = 0;
3881         gchar *end;
3882         gdouble val;
3883
3884         if (str == NULL || *str == 0) return TRUE;
3885         while (*str)
3886         {
3887                 val = g_strtod(str, &end);
3888                 if (str != end)
3889                 { // Found a numeric value
3890                         fields++;
3891                         // negative max_fields means infinate
3892                         if (max_fields >= 0 && fields > max_fields) return FALSE;
3893                         if (*end == 0)
3894                                 return TRUE;
3895                         if (*end != ':')
3896                                 return FALSE;
3897                         str = end + 1;
3898                 }
3899                 else
3900                         return FALSE;
3901         }
3902         return FALSE;
3903 }
3904
3905 gboolean
3906 ghb_validate_filters(signal_user_data_t *ud)
3907 {
3908         gchar *str;
3909         gint index;
3910         gchar *message;
3911
3912         gboolean decomb_deint = ghb_settings_get_boolean(ud->settings, "PictureDecombDeinterlace");
3913         // deinte
3914         index = ghb_settings_combo_int(ud->settings, "PictureDeinterlace");
3915         if (!decomb_deint && index == 1)
3916         {
3917                 str = ghb_settings_get_string(ud->settings, "PictureDeinterlaceCustom");
3918                 if (!ghb_validate_filter_string(str, -1))
3919                 {
3920                         message = g_strdup_printf(
3921                                                 "Invalid Deinterlace Settings:\n\n%s\n",
3922                                                 str);
3923                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3924                         g_free(message);
3925                         g_free(str);
3926                         return FALSE;
3927                 }
3928                 g_free(str);
3929         }
3930         // detel
3931         index = ghb_settings_combo_int(ud->settings, "PictureDetelecine");
3932         if (index == 1)
3933         {
3934                 str = ghb_settings_get_string(ud->settings, "PictureDetelecineCustom");
3935                 if (!ghb_validate_filter_string(str, -1))
3936                 {
3937                         message = g_strdup_printf(
3938                                                 "Invalid Detelecine Settings:\n\n%s\n",
3939                                                 str);
3940                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3941                         g_free(message);
3942                         g_free(str);
3943                         return FALSE;
3944                 }
3945                 g_free(str);
3946         }
3947         // decomb
3948         index = ghb_settings_combo_int(ud->settings, "PictureDecomb");
3949         if (decomb_deint && index == 1)
3950         {
3951                 str = ghb_settings_get_string(ud->settings, "PictureDecombCustom");
3952                 if (!ghb_validate_filter_string(str, -1))
3953                 {
3954                         message = g_strdup_printf(
3955                                                 "Invalid Decomb Settings:\n\n%s\n",
3956                                                 str);
3957                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3958                         g_free(message);
3959                         g_free(str);
3960                         return FALSE;
3961                 }
3962                 g_free(str);
3963         }
3964         // denois
3965         index = ghb_settings_combo_int(ud->settings, "PictureDenoise");
3966         if (index == 1)
3967         {
3968                 str = ghb_settings_get_string(ud->settings, "PictureDenoiseCustom");
3969                 if (!ghb_validate_filter_string(str, -1))
3970                 {
3971                         message = g_strdup_printf(
3972                                                 "Invalid Denoise Settings:\n\n%s\n",
3973                                                 str);
3974                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3975                         g_free(str);
3976                         g_free(message);
3977                         return FALSE;
3978                 }
3979                 g_free(str);
3980         }
3981         return TRUE;
3982 }
3983
3984 gboolean
3985 ghb_validate_video(signal_user_data_t *ud)
3986 {
3987         gint vcodec, mux;
3988         gchar *message;
3989
3990         mux = ghb_settings_combo_int(ud->settings, "FileFormat");
3991         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
3992         if ((mux == HB_MUX_MP4) && (vcodec == HB_VCODEC_THEORA))
3993         {
3994                 // mp4/theora combination is not supported.
3995                 message = g_strdup_printf(
3996                                         "Theora is not supported in the MP4 container.\n\n"
3997                                         "You should choose a different video codec or container.\n"
3998                                         "If you continue, FFMPEG will be chosen for you.");
3999                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4000                 {
4001                         g_free(message);
4002                         return FALSE;
4003                 }
4004                 g_free(message);
4005                 vcodec = HB_VCODEC_FFMPEG;
4006                 ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
4007         }
4008         return TRUE;
4009 }
4010
4011 gboolean
4012 ghb_validate_subtitles(signal_user_data_t *ud)
4013 {
4014         hb_list_t  * list;
4015         hb_title_t * title;
4016         gchar *message;
4017
4018         if (h_scan == NULL) return FALSE;
4019         list = hb_get_titles( h_scan );
4020         if( !hb_list_count( list ) )
4021         {
4022                 /* No valid title, stop right there */
4023                 g_message("No title found.\n");
4024                 return FALSE;
4025         }
4026
4027         gint titleindex;
4028
4029         titleindex = ghb_settings_combo_int(ud->settings, "title");
4030     title = hb_list_item( list, titleindex );
4031         if (title == NULL) return FALSE;
4032
4033         const GValue *slist, *settings;
4034         gint count, ii, source;
4035         gboolean burned, one_burned = FALSE;
4036
4037         slist = ghb_settings_get_value(ud->settings, "subtitle_list");
4038         count = ghb_array_len(slist);
4039         for (ii = 0; ii < count; ii++)
4040         {
4041                 settings = ghb_array_get_nth(slist, ii);
4042                 source = ghb_settings_get_int(settings, "SubtitleSource");
4043                 burned = ghb_settings_get_boolean(settings, "SubtitleBurned");
4044                 if (burned && one_burned)
4045                 {
4046                         // MP4 can only handle burned vobsubs.  make sure there isn't
4047                         // already something burned in the list
4048                         message = g_strdup_printf(
4049                         "Only one subtitle may be burned into the video.\n\n"
4050                                 "You should change your subtitle selections.\n"
4051                                 "If you continue, some subtitles will be lost.");
4052                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4053                         {
4054                                 g_free(message);
4055                                 return FALSE;
4056                         }
4057                         g_free(message);
4058                         break;
4059                 }
4060                 else if (burned)
4061                 {
4062                         one_burned = TRUE;
4063                 }
4064                 if (source == SRTSUB)
4065                 {
4066                         gchar *filename;
4067
4068                         filename = ghb_settings_get_string(settings, "SrtFile");
4069                         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
4070                         {
4071                                 message = g_strdup_printf(
4072                                 "Srt file does not exist or not a regular file.\n\n"
4073                                         "You should choose a valid file.\n"
4074                                         "If you continue, this subtitle will be ignored.");
4075                                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, 
4076                                         "Cancel", "Continue"))
4077                                 {
4078                                         g_free(message);
4079                                         return FALSE;
4080                                 }
4081                                 g_free(message);
4082                                 break;
4083                         }
4084                 }
4085         }
4086         return TRUE;
4087 }
4088
4089 gint
4090 ghb_select_audio_codec(GValue *settings, hb_audio_config_t *aconfig, gint acodec)
4091 {
4092         gint mux = ghb_settings_combo_int(settings, "FileFormat");
4093
4094         guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK;
4095         if (mux == HB_MUX_MP4)
4096         {
4097                 if ((acodec & in_codec & HB_ACODEC_AC3))
4098                 {
4099                         return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4100                 }
4101                 else if (acodec & HB_ACODEC_AC3)
4102                 {
4103                         return HB_ACODEC_AC3;
4104                 }
4105                 else if (acodec & HB_ACODEC_LAME)
4106                 {
4107                         return HB_ACODEC_LAME;
4108                 }
4109                 else if (acodec & HB_ACODEC_FAAC)
4110                 {
4111                         return HB_ACODEC_FAAC;
4112                 }
4113                 else
4114                 {
4115                         return HB_ACODEC_FAAC;
4116                 }
4117         }
4118         else
4119         {
4120                 if ((acodec & in_codec & HB_ACODEC_PASS_MASK))
4121                 {
4122                         return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4123                 }
4124                 else if (acodec & HB_ACODEC_AC3)
4125                 {
4126                         return HB_ACODEC_AC3;
4127                 }
4128                 else if (acodec & HB_ACODEC_VORBIS)
4129                 {
4130                         return HB_ACODEC_VORBIS;
4131                 }
4132                 else if (acodec & HB_ACODEC_LAME)
4133                 {
4134                         return HB_ACODEC_LAME;
4135                 }
4136                 else if (acodec & HB_ACODEC_FAAC)
4137                 {
4138                         return HB_ACODEC_FAAC;
4139                 }
4140                 else
4141                 {
4142                         return HB_ACODEC_LAME;
4143                 }
4144         }
4145 }
4146
4147 gboolean
4148 ghb_validate_audio(signal_user_data_t *ud)
4149 {
4150         hb_list_t  * list;
4151         hb_title_t * title;
4152         gchar *message;
4153         GValue *value;
4154
4155         if (h_scan == NULL) return FALSE;
4156         list = hb_get_titles( h_scan );
4157         if( !hb_list_count( list ) )
4158         {
4159                 /* No valid title, stop right there */
4160                 g_message("No title found.\n");
4161                 return FALSE;
4162         }
4163
4164         gint titleindex;
4165
4166         titleindex = ghb_settings_combo_int(ud->settings, "title");
4167     title = hb_list_item( list, titleindex );
4168         if (title == NULL) return FALSE;
4169         gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
4170
4171         const GValue *audio_list;
4172         gint count, ii;
4173
4174         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
4175         count = ghb_array_len(audio_list);
4176         for (ii = 0; ii < count; ii++)
4177         {
4178                 GValue *asettings;
4179             hb_audio_config_t *aconfig;
4180
4181                 asettings = ghb_array_get_nth(audio_list, ii);
4182                 gint track = ghb_settings_combo_int(asettings, "AudioTrack");
4183                 gint codec = ghb_settings_combo_int(asettings, "AudioEncoder");
4184                 if (codec == HB_ACODEC_ANY)
4185                         continue;
4186
4187         aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
4188                                                                                         title->list_audio, track );
4189                 if ( ghb_audio_is_passthru(codec) &&
4190                         !(ghb_audio_can_passthru(aconfig->in.codec) && 
4191                          (aconfig->in.codec & codec)))
4192                 {
4193                         // Not supported.  AC3 is passthrough only, so input must be AC3
4194                         message = g_strdup_printf(
4195                                                 "The source does not support Pass-Thru.\n\n"
4196                                                 "You should choose a different audio codec.\n"
4197                                                 "If you continue, one will be chosen for you.");
4198                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4199                         {
4200                                 g_free(message);
4201                                 return FALSE;
4202                         }
4203                         g_free(message);
4204                         if ((codec & HB_ACODEC_AC3) ||
4205                                 aconfig->in.codec == HB_ACODEC_DCA)
4206                         {
4207                                 codec = HB_ACODEC_AC3;
4208                         }
4209                         else if (mux == HB_MUX_MKV)
4210                         {
4211                                 codec = HB_ACODEC_LAME;
4212                         }
4213                         else
4214                         {
4215                                 codec = HB_ACODEC_FAAC;
4216                         }
4217                         value = ghb_lookup_acodec_value(codec);
4218                         ghb_settings_take_value(asettings, "AudioEncoder", value);
4219                 }
4220                 gchar *a_unsup = NULL;
4221                 gchar *mux_s = NULL;
4222                 if (mux == HB_MUX_MP4)
4223                 { 
4224                         mux_s = "MP4";
4225                         // mp4/vorbis|DTS combination is not supported.
4226                         if (codec == HB_ACODEC_VORBIS)
4227                         {
4228                                 a_unsup = "Vorbis";
4229                                 codec = HB_ACODEC_FAAC;
4230                         }
4231                         if (codec == HB_ACODEC_DCA)
4232                         {
4233                                 a_unsup = "DTS";
4234                                 codec = HB_ACODEC_AC3;
4235                         }
4236                 }
4237                 if (a_unsup)
4238                 {
4239                         message = g_strdup_printf(
4240                                                 "%s is not supported in the %s container.\n\n"
4241                                                 "You should choose a different audio codec.\n"
4242                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
4243                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4244                         {
4245                                 g_free(message);
4246                                 return FALSE;
4247                         }
4248                         g_free(message);
4249                         value = ghb_lookup_acodec_value(codec);
4250                         ghb_settings_take_value(asettings, "AudioEncoder", value);
4251                 }
4252
4253                 gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
4254                 gboolean allow_mono = TRUE;
4255                 gboolean allow_stereo = TRUE;
4256                 gboolean allow_dolby = TRUE;
4257                 gboolean allow_dpl2 = TRUE;
4258                 gboolean allow_6ch = TRUE;
4259                 allow_mono = TRUE;
4260
4261                 gint best = hb_get_best_mixdown(codec, aconfig->in.channel_layout, 0);
4262
4263                 allow_stereo = best >= HB_AMIXDOWN_STEREO;
4264                 allow_dolby = best >= HB_AMIXDOWN_DOLBY;
4265                 allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
4266                 allow_6ch = best >= HB_AMIXDOWN_6CH;
4267
4268                 gchar *mix_unsup = NULL;
4269                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
4270                 {
4271                         mix_unsup = "mono";
4272                 }
4273                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
4274                 {
4275                         mix_unsup = "stereo";
4276                 }
4277                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
4278                 {
4279                         mix_unsup = "Dolby";
4280                 }
4281                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
4282                 {
4283                         mix_unsup = "Dolby Pro Logic II";
4284                 }
4285                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
4286                 {
4287                         mix_unsup = "6 Channel";
4288                 }
4289                 if (mix_unsup)
4290                 {
4291                         message = g_strdup_printf(
4292                                                 "The source audio does not support %s mixdown.\n\n"
4293                                                 "You should choose a different mixdown.\n"
4294                                                 "If you continue, one will be chosen for you.", mix_unsup);
4295                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4296                         {
4297                                 g_free(message);
4298                                 return FALSE;
4299                         }
4300                         g_free(message);
4301                         mix = ghb_get_best_mix(aconfig, codec, mix);
4302                         value = get_amix_value(mix);
4303                         ghb_settings_take_value(asettings, "AudioMixdown", value);
4304                 }
4305         }
4306         return TRUE;
4307 }
4308
4309 gboolean
4310 ghb_validate_vquality(GValue *settings)
4311 {
4312         gint vcodec;
4313         gchar *message;
4314         gint min, max;
4315
4316         if (ghb_settings_get_boolean(settings, "nocheckvquality")) return TRUE;
4317         vcodec = ghb_settings_combo_int(settings, "VideoEncoder");
4318         gdouble vquality;
4319         vquality = ghb_settings_get_double(settings, "VideoQualitySlider");
4320         if (ghb_settings_get_boolean(settings, "vquality_type_constant"))
4321         {
4322                 switch (vcodec)
4323                 {
4324                         case HB_VCODEC_X264:
4325                         {
4326                                 min = 16;
4327                                 max = 30;
4328                         } break;
4329
4330                         case HB_VCODEC_FFMPEG:
4331                         {
4332                                 min = 1;
4333                                 max = 8;
4334                         } break;
4335
4336                         case HB_VCODEC_THEORA:
4337                         {
4338                                 min = 0;
4339                                 max = 63;
4340                         } break;
4341
4342                         default:
4343                         {
4344                                 min = 48;
4345                                 max = 62;
4346                         } break;
4347                 }
4348                 if (vcodec == HB_VCODEC_X264 && vquality == 0.0)
4349                 {
4350                         message = g_strdup_printf(
4351                                                 "Warning: lossless h.264 selected\n\n"
4352                                                 "Lossless h.264 is not well supported by\n"
4353                                                 "many players and editors.\n\n"
4354                         "It will produce enormous output files.\n\n"
4355                                                 "Are you sure you wish to use this setting?",
4356                                                 (gint)vquality, min, max);
4357                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
4358                                                                         "Cancel", "Continue"))
4359                         {
4360                                 g_free(message);
4361                                 return FALSE;
4362                         }
4363                         g_free(message);
4364                 }
4365                 else if (vquality < min || vquality > max)
4366                 {
4367                         message = g_strdup_printf(
4368                                                 "Interesting video quality choice: %d\n\n"
4369                                                 "Typical values range from %d to %d.\n\n"
4370                                                 "Are you sure you wish to use this setting?",
4371                                                 (gint)vquality, min, max);
4372                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
4373                                                                         "Cancel", "Continue"))
4374                         {
4375                                 g_free(message);
4376                                 return FALSE;
4377                         }
4378                         g_free(message);
4379                 }
4380         }
4381         return TRUE;
4382 }
4383
4384 static void
4385 add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
4386 {
4387         hb_list_t  * list;
4388         hb_title_t * title;
4389         hb_job_t   * job;
4390         static gchar *x264opts;
4391         gint sub_id = 0;
4392         gboolean tweaks = FALSE;
4393         gchar *detel_str = NULL;
4394         gchar *decomb_str = NULL;
4395         gchar *deint_str = NULL;
4396         gchar *deblock_str = NULL;
4397         gchar *denoise_str = NULL;
4398         gchar *dest_str = NULL;
4399
4400         g_debug("add_job()\n");
4401         if (h == NULL) return;
4402         list = hb_get_titles( h );
4403         if( !hb_list_count( list ) )
4404         {
4405                 /* No valid title, stop right there */
4406                 return;
4407         }
4408
4409     title = hb_list_item( list, titleindex );
4410         if (title == NULL) return;
4411
4412         /* Set job settings */
4413         job   = title->job;
4414         if (job == NULL) return;
4415
4416         job->angle = ghb_settings_get_int(js, "angle");
4417         job->start_at_preview = ghb_settings_get_int(js, "start_frame") + 1;
4418         if (job->start_at_preview)
4419         {
4420                 job->seek_points = ghb_settings_get_int(js, "preview_count");
4421                 job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL;
4422         }
4423
4424         tweaks = ghb_settings_get_boolean(js, "allow_tweaks");
4425         job->mux = ghb_settings_combo_int(js, "FileFormat");
4426         if (job->mux == HB_MUX_MP4)
4427         {
4428                 job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile");
4429                 job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize");
4430         }
4431         else
4432         {
4433                 job->largeFileSize = FALSE;
4434                 job->mp4_optimize = FALSE;
4435         }
4436         if (!job->start_at_preview)
4437         {
4438                 gint start, end;
4439                 gint num_chapters = hb_list_count(title->list_chapter);
4440                 gint duration = title->duration / 90000;
4441                 job->chapter_markers = FALSE;
4442                 job->chapter_start = 1;
4443                 job->chapter_end = num_chapters;
4444
4445                 if (ghb_settings_combo_int(js, "PtoPType") == 0)
4446                 {
4447                         start = ghb_settings_get_int(js, "start_point");
4448                         end = ghb_settings_get_int(js, "end_point");
4449                         job->chapter_start = MIN( num_chapters, start );
4450                         job->chapter_end   = MAX( job->chapter_start, end );
4451
4452                 }
4453                 if (ghb_settings_combo_int(js, "PtoPType") == 1)
4454                 {
4455                         start = ghb_settings_get_int(js, "start_point");
4456                         end = ghb_settings_get_int(js, "end_point");
4457                         job->pts_to_start = (int64_t)MIN(duration-1, start) * 90000;
4458                         job->pts_to_stop = (int64_t)MAX(start+1, end) * 90000 - 
4459                                                                 job->pts_to_start;
4460                 }
4461                 if (ghb_settings_combo_int(js, "PtoPType") == 2)
4462                 {
4463                         start = ghb_settings_get_int(js, "start_point");
4464                         end = ghb_settings_get_int(js, "end_point");
4465                         gint64 max_frames;
4466                         max_frames = (gint64)duration * title->rate / title->rate_base;
4467                         job->frame_to_start = (int64_t)MIN(max_frames-1, start-1);
4468                         job->frame_to_stop = (int64_t)MAX(start, end-1) - 
4469                                                                  job->frame_to_start;
4470                 }
4471                 if (job->chapter_start != job->chapter_end)
4472                 {
4473                         job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
4474                 }
4475                 if (job->chapter_start == job->chapter_end)
4476                         job->chapter_markers = 0;
4477                 if ( job->chapter_markers )
4478                 {
4479                         GValue *chapters;
4480                         GValue *chapter;
4481                         gint chap;
4482                         gint count;
4483
4484                         chapters = ghb_settings_get_value(js, "chapter_list");
4485                         count = ghb_array_len(chapters);
4486                         for(chap = 0; chap < count; chap++)
4487                         {
4488                                 hb_chapter_t * chapter_s;
4489                                 gchar *name;
4490
4491                                 name = NULL;
4492                                 chapter = ghb_array_get_nth(chapters, chap);
4493                                 name = ghb_value_string(chapter); 
4494                                 if (name == NULL)
4495                                 {
4496                                         name = g_strdup_printf ("Chapter %2d", chap+1);
4497                                 }
4498                                 chapter_s = hb_list_item( job->title->list_chapter, chap);
4499                                 strncpy(chapter_s->title, name, 1023);
4500                                 chapter_s->title[1023] = '\0';
4501                                 g_free(name);
4502                         }
4503                 }
4504         }
4505         job->crop[0] = ghb_settings_get_int(js, "PictureTopCrop");
4506         job->crop[1] = ghb_settings_get_int(js, "PictureBottomCrop");
4507         job->crop[2] = ghb_settings_get_int(js, "PictureLeftCrop");
4508         job->crop[3] = ghb_settings_get_int(js, "PictureRightCrop");
4509
4510         
4511         gboolean decomb_deint = ghb_settings_get_boolean(js, "PictureDecombDeinterlace");
4512         gint decomb = ghb_settings_combo_int(js, "PictureDecomb");
4513         gint deint = ghb_settings_combo_int(js, "PictureDeinterlace");
4514         if (!decomb_deint)
4515                 job->deinterlace = (deint != 0) ? 1 : 0;
4516         else
4517                 job->deinterlace = 0;
4518     job->grayscale   = ghb_settings_get_boolean(js, "VideoGrayScale");
4519
4520         gboolean keep_aspect;
4521         keep_aspect = ghb_settings_get_boolean(js, "PictureKeepRatio");
4522         job->anamorphic.mode = ghb_settings_combo_int(js, "PicturePAR");
4523         job->modulus = ghb_settings_combo_int(js, "PictureModulus");
4524         if (job->anamorphic.mode)
4525         {
4526                 job->anamorphic.par_width = title->pixel_aspect_width;
4527                 job->anamorphic.par_height = title->pixel_aspect_height;
4528                 job->anamorphic.dar_width = 0;
4529                 job->anamorphic.dar_height = 0;
4530
4531                 if (job->anamorphic.mode == 3 && !keep_aspect)
4532                 {
4533                         job->anamorphic.keep_display_aspect = 0;
4534                         job->anamorphic.par_width = 
4535                                 ghb_settings_get_int(js, "PicturePARWidth");
4536                         job->anamorphic.par_height = 
4537                                 ghb_settings_get_int(js, "PicturePARHeight");
4538                 }
4539                 else
4540                 {
4541                         job->anamorphic.keep_display_aspect = 1;
4542                 }
4543         }
4544
4545         /* Add selected filters */
4546         job->filters = hb_list_init();
4547         gint detel = ghb_settings_combo_int(js, "PictureDetelecine");
4548         if ( detel )
4549         {
4550                 if (detel != 1)
4551                 {
4552                         if (detel_opts.map[detel].svalue != NULL)
4553                                 detel_str = g_strdup(detel_opts.map[detel].svalue);
4554                 }
4555                 else
4556                         detel_str = ghb_settings_get_string(js, "PictureDetelecineCustom");
4557                 hb_filter_detelecine.settings = detel_str;
4558                 hb_list_add( job->filters, &hb_filter_detelecine );
4559         }
4560         if ( decomb_deint && decomb )
4561         {
4562                 if (decomb != 1)
4563                 {
4564                         if (decomb_opts.map[decomb].svalue != NULL)
4565                                 decomb_str = g_strdup(decomb_opts.map[decomb].svalue);
4566                 }
4567                 else
4568                         decomb_str = ghb_settings_get_string(js, "PictureDecombCustom");
4569                 hb_filter_decomb.settings = decomb_str;
4570                 hb_list_add( job->filters, &hb_filter_decomb );
4571         }
4572         if( job->deinterlace )
4573         {
4574                 if (deint != 1)
4575                 {
4576                         if (deint_opts.map[deint].svalue != NULL)
4577                                 deint_str = g_strdup(deint_opts.map[deint].svalue);
4578                 }
4579                 else
4580                         deint_str = ghb_settings_get_string(js, "PictureDeinterlaceCustom");
4581                 hb_filter_deinterlace.settings = deint_str;
4582                 hb_list_add( job->filters, &hb_filter_deinterlace );
4583         }
4584         gint deblock = ghb_settings_get_int(js, "PictureDeblock");
4585         if( deblock >= 5 )
4586         {
4587                 deblock_str = g_strdup_printf("%d", deblock);
4588                 hb_filter_deblock.settings = deblock_str;
4589                 hb_list_add( job->filters, &hb_filter_deblock );
4590         }
4591         gint denoise = ghb_settings_combo_int(js, "PictureDenoise");
4592         if( denoise )
4593         {
4594                 if (denoise != 1)
4595                 {
4596                         if (denoise_opts.map[denoise].svalue != NULL)
4597                                 denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
4598                 }
4599                 else
4600                         denoise_str = ghb_settings_get_string(js, "PictureDenoiseCustom");
4601                 hb_filter_denoise.settings = denoise_str;
4602                 hb_list_add( job->filters, &hb_filter_denoise );
4603         }
4604         job->width = ghb_settings_get_int(js, "scale_width");
4605         job->height = ghb_settings_get_int(js, "scale_height");
4606
4607         job->vcodec = ghb_settings_combo_int(js, "VideoEncoder");
4608         if ((job->mux == HB_MUX_MP4 ) && (job->vcodec == HB_VCODEC_THEORA))
4609         {
4610                 // mp4/theora combination is not supported.
4611                 job->vcodec = HB_VCODEC_FFMPEG;
4612         }
4613         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
4614         {
4615                 job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible");
4616         }
4617         if (ghb_settings_get_boolean(js, "vquality_type_constant"))
4618         {
4619                 gdouble vquality;
4620                 vquality = ghb_settings_get_double(js, "VideoQualitySlider");
4621                 job->vquality =  vquality;
4622                 job->vbitrate = 0;
4623         }
4624         else if (ghb_settings_get_boolean(js, "vquality_type_bitrate"))
4625         {
4626                 job->vquality = -1.0;
4627                 job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
4628         }
4629
4630         gint vrate = ghb_settings_combo_int(js, "VideoFramerate");
4631         if( vrate == 0 )
4632         {
4633                 job->vrate = title->rate;
4634                 job->vrate_base = title->rate_base;
4635         }
4636         else
4637         {
4638                 job->vrate = 27000000;
4639                 job->vrate_base = vrate;
4640         }
4641         if (ghb_settings_get_boolean(js, "VideoFrameratePFR"))
4642                 job->cfr = 2;
4643         else if (ghb_settings_get_boolean(js, "VideoFramerateCFR"))
4644                 job->cfr = 1;
4645         else
4646                 job->cfr = 0;
4647
4648         const GValue *audio_list;
4649         gint count, ii;
4650         gint tcount = 0;
4651         
4652         audio_list = ghb_settings_get_value(js, "audio_list");
4653         count = ghb_array_len(audio_list);
4654         for (ii = 0; ii < count; ii++)
4655         {
4656                 GValue *asettings;
4657             hb_audio_config_t audio;
4658             hb_audio_config_t *aconfig;
4659                 gint acodec;
4660
4661                 hb_audio_config_init(&audio);
4662                 asettings = ghb_array_get_nth(audio_list, ii);
4663                 audio.in.track = ghb_settings_get_int(asettings, "AudioTrack");
4664                 audio.out.track = tcount;
4665
4666         aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
4667                                                                         title->list_audio, audio.in.track );
4668
4669                 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
4670                 audio.out.codec = ghb_select_audio_codec(js, aconfig, acodec);
4671
4672         audio.out.dynamic_range_compression = 
4673                         ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
4674         if (audio.out.dynamic_range_compression < 1.0)
4675                 audio.out.dynamic_range_compression = 0.0;
4676
4677                 // It would be better if this were done in libhb for us, but its not yet.
4678                 if (ghb_audio_is_passthru(audio.out.codec))
4679                 {
4680                         audio.out.mixdown = 0;
4681                 }
4682                 else
4683                 {
4684                         audio.out.mixdown = ghb_settings_combo_int(asettings, "AudioMixdown");
4685                         // Make sure the mixdown is valid and pick a new one if not.
4686                         audio.out.mixdown = ghb_get_best_mix(aconfig, audio.out.codec, 
4687                                                                                                         audio.out.mixdown);
4688                         audio.out.bitrate = 
4689                                 ghb_settings_combo_int(asettings, "AudioBitrate");
4690                         gint srate = ghb_settings_combo_int(asettings, "AudioSamplerate");
4691                         if (srate == 0) // 0 is same as source
4692                                 audio.out.samplerate = aconfig->in.samplerate;
4693                         else
4694                                 audio.out.samplerate = srate;
4695
4696                         audio.out.bitrate = hb_get_best_audio_bitrate(
4697                                 audio.out.codec, audio.out.bitrate, 
4698                                 audio.out.samplerate, audio.out.mixdown);
4699                 }
4700
4701                 // Add it to the jobs audio list
4702         hb_audio_add( job, &audio );
4703                 tcount++;
4704         }
4705         // I was tempted to move this up with the reset of the video quality
4706         // settings, but I suspect the settings above need to be made
4707         // first in order for hb_calc_bitrate to be accurate.
4708         if (ghb_settings_get_boolean(js, "vquality_type_target"))
4709         {
4710                 gint size;
4711                 
4712                 size = ghb_settings_get_int(js, "VideoTargetSize");
4713         job->vbitrate = hb_calc_bitrate( job, size );
4714                 job->vquality = -1.0;
4715         }
4716
4717         dest_str = ghb_settings_get_string(js, "destination");
4718         job->file = dest_str;
4719
4720         const GValue *subtitle_list;
4721         gint subtitle;
4722         gboolean force, burned, def, one_burned = FALSE;
4723         
4724         ghb_settings_set_boolean(js, "subtitle_scan", FALSE);
4725         subtitle_list = ghb_settings_get_value(js, "subtitle_list");
4726         count = ghb_array_len(subtitle_list);
4727         for (ii = 0; ii < count; ii++)
4728         {
4729                 GValue *ssettings;
4730                 gint source;
4731
4732                 ssettings = ghb_array_get_nth(subtitle_list, ii);
4733
4734                 force = ghb_settings_get_boolean(ssettings, "SubtitleForced");
4735                 burned = ghb_settings_get_boolean(ssettings, "SubtitleBurned");
4736                 def = ghb_settings_get_boolean(ssettings, "SubtitleDefaultTrack");
4737                 source = ghb_settings_get_int(ssettings, "SubtitleSource");
4738
4739                 if (source == SRTSUB)
4740                 {
4741                 hb_subtitle_config_t sub_config;
4742                         gchar *filename, *lang, *code;
4743
4744                         filename = ghb_settings_get_string(ssettings, "SrtFile");
4745                         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
4746                         {
4747                                 continue;
4748                         }
4749                         sub_config.offset = ghb_settings_get_int(ssettings, "SrtOffset");
4750                         lang = ghb_settings_get_string(ssettings, "SrtLanguage");
4751                         code = ghb_settings_get_string(ssettings, "SrtCodeset");
4752                         strncpy(sub_config.src_filename, filename, 255);
4753                         sub_config.src_filename[255] = 0;
4754                         strncpy(sub_config.src_codeset, code, 39);
4755                         sub_config.src_codeset[39] = 0;
4756                         sub_config.force = 0;
4757                         sub_config.dest = PASSTHRUSUB;
4758                         sub_config.default_track = def;
4759
4760                         hb_srt_add( job, &sub_config, lang);
4761
4762                         g_free(filename);
4763                         g_free(lang);
4764                         g_free(code);
4765                         continue;
4766                 }
4767
4768                 subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack");
4769                 if (subtitle == -1)
4770                 {
4771                         if (!burned)
4772                         {
4773                                 job->select_subtitle_config.dest = PASSTHRUSUB;
4774                         }
4775                         else if (burned)
4776                         {
4777                                 // Only allow one subtitle to be burned into the video
4778                                 if (one_burned)
4779                                         continue;
4780                                 job->select_subtitle_config.dest = RENDERSUB;
4781                                 one_burned = TRUE;
4782                         }
4783                         job->select_subtitle_config.force = force;
4784                         job->select_subtitle_config.default_track = def;
4785                         job->indepth_scan = 1;
4786                         ghb_settings_set_boolean(js, "subtitle_scan", TRUE);
4787                 }
4788                 else if (subtitle >= 0)
4789                 {
4790                 hb_subtitle_t * subt;
4791                 hb_subtitle_config_t sub_config;
4792
4793                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
4794                         if (subt != NULL)
4795                         {
4796                                 sub_config = subt->config;
4797                                 if (!burned)
4798                                 {
4799                                         sub_config.dest = PASSTHRUSUB;
4800                                 }
4801                                 else if ( burned && canBurn(subt->source) )
4802                                 {
4803                                         // Only allow one subtitle to be burned into the video
4804                                         if (one_burned)
4805                                                 continue;
4806                                         sub_config.dest = RENDERSUB;
4807                                         one_burned = TRUE;
4808                                 }
4809                                 sub_config.force = force;
4810                                 sub_config.default_track = def;
4811                         hb_subtitle_add( job, &sub_config, subtitle );
4812                         }
4813                 }
4814         }
4815
4816         // TODO: libhb holds onto a reference to the x264opts and is not
4817         // finished with it until encoding the job is done.  But I can't
4818         // find a way to get at the job before it is removed in order to
4819         // free up the memory I am allocating here.
4820         // The short story is THIS LEAKS.
4821         x264opts = ghb_build_x264opts_string(js);
4822         
4823         if( *x264opts == '\0' )
4824         {
4825                 g_free(x264opts);
4826                 x264opts = NULL;
4827         }
4828
4829         if (job->indepth_scan == 1)
4830         {
4831                 // Subtitle scan. Look for subtitle matching audio language
4832
4833                 /*
4834                  * When subtitle scan is enabled do a fast pre-scan job
4835                  * which will determine which subtitles to enable, if any.
4836                  */
4837                 job->pass = -1;
4838                 job->indepth_scan = 1;
4839                 job->x264opts = NULL;
4840
4841                 /*
4842                  * Add the pre-scan job
4843                  */
4844                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4845                 hb_add( h, job );
4846         }
4847
4848         if( ghb_settings_get_boolean(js, "VideoTwoPass") &&
4849                 !ghb_settings_get_boolean(js, "vquality_type_constant"))
4850         {
4851                 /*
4852                  * If subtitle_scan is enabled then only turn it on
4853                  * for the second pass and then off again for the
4854                  * second.
4855                  */
4856                 job->pass = 1;
4857                 job->indepth_scan = 0;
4858
4859                 /*
4860                  * If turbo options have been selected then append them
4861                  * to the x264opts now (size includes one ':' and the '\0')
4862                  */
4863                 if( ghb_settings_get_boolean(js, "VideoTurboTwoPass") )
4864                 {
4865                         gchar *tmp_x264opts;
4866                         gchar *extra_opts;
4867                         gint badapt;
4868
4869                         badapt = ghb_lookup_badapt(x264opts);
4870                         if (badapt == 2)
4871                         {
4872                                 extra_opts = g_strdup_printf("%s", turbo_opts);
4873                         }
4874                         else
4875                         {
4876                                 extra_opts = g_strdup_printf("%s:weightb=0", turbo_opts);
4877                         }
4878         
4879                         if ( x264opts )
4880                         {
4881                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, extra_opts);
4882                         } 
4883                         else 
4884                         {
4885                                 /*
4886                                  * No x264opts to modify, but apply the turbo options
4887                                  * anyway as they may be modifying defaults
4888                                  */
4889                                 tmp_x264opts = g_strdup_printf("%s", extra_opts);
4890                         }
4891                         g_free(extra_opts);
4892
4893                         job->x264opts = tmp_x264opts;
4894                 }
4895                 else
4896                 {
4897                         job->x264opts = x264opts;
4898                 }
4899                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4900                 hb_add( h, job );
4901                 //if (job->x264opts != NULL)
4902                 //      g_free(job->x264opts);
4903
4904                 job->pass = 2;
4905                 /*
4906                  * On the second pass we turn off subtitle scan so that we
4907                  * can actually encode using any subtitles that were auto
4908                  * selected in the first pass (using the whacky select-subtitle
4909                  * attribute of the job).
4910                  */
4911                 job->indepth_scan = 0;
4912                 job->x264opts = x264opts;
4913                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4914                 hb_add( h, job );
4915                 //if (job->x264opts != NULL)
4916                 //      g_free(job->x264opts);
4917         }
4918         else
4919         {
4920                 job->x264opts = x264opts;
4921                 job->indepth_scan = 0;
4922                 job->pass = 0;
4923                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4924                 hb_add( h, job );
4925                 //if (job->x264opts != NULL)
4926                 //      g_free(job->x264opts);
4927         }
4928
4929         // clean up audio list
4930         gint num_audio_tracks = hb_list_count(job->list_audio);
4931         for(ii = 0; ii < num_audio_tracks; ii++)
4932         {
4933                 hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
4934                 hb_list_rem(job->list_audio, audio);
4935                 free(audio);
4936         }
4937
4938         // clean up subtitle list
4939         gint num_subtitle_tracks = hb_list_count(job->list_subtitle);
4940         for(ii = 0; ii < num_subtitle_tracks; ii++)
4941         {
4942                 hb_subtitle_t *subtitle = hb_list_item(job->list_subtitle, 0);
4943                 hb_list_rem(job->list_subtitle, subtitle);
4944                 free(subtitle);
4945         }
4946
4947         if (detel_str) g_free(detel_str);
4948         if (decomb_str) g_free(decomb_str);
4949         if (deint_str) g_free(deint_str);
4950         if (deblock_str) g_free(deblock_str);
4951         if (denoise_str) g_free(denoise_str);
4952         if (dest_str) g_free(dest_str);
4953 }
4954
4955 void
4956 ghb_add_job(GValue *js, gint unique_id)
4957 {
4958         // Since I'm doing a scan of the single title I want just prior 
4959         // to adding the job, there is only the one title to choose from.
4960         add_job(h_queue, js, unique_id, 0);
4961 }
4962
4963 void
4964 ghb_add_live_job(GValue *js, gint unique_id)
4965 {
4966         // Since I'm doing a scan of the single title I want just prior 
4967         // to adding the job, there is only the one title to choose from.
4968         gint titleindex = ghb_settings_combo_int(js, "title");
4969         add_job(h_scan, js, unique_id, titleindex);
4970 }
4971
4972 void
4973 ghb_remove_job(gint unique_id)
4974 {
4975     hb_job_t * job;
4976     gint ii;
4977         
4978         // Multiples passes all get the same id
4979         // remove them all.
4980         // Go backwards through list, so reordering doesn't screw me.
4981         ii = hb_count(h_queue) - 1;
4982     while ((job = hb_job(h_queue, ii--)) != NULL)
4983     {
4984         if ((job->sequence_id & 0xFFFFFF) == unique_id)
4985                         hb_rem(h_queue, job);
4986     }
4987 }
4988
4989 void
4990 ghb_start_queue()
4991 {
4992         hb_start( h_queue );
4993 }
4994
4995 void
4996 ghb_stop_queue()
4997 {
4998         hb_stop( h_queue );
4999 }
5000
5001 void
5002 ghb_start_live_encode()
5003 {
5004         hb_start( h_scan );
5005 }
5006
5007 void
5008 ghb_stop_live_encode()
5009 {
5010         hb_stop( h_scan );
5011 }
5012
5013 void
5014 ghb_pause_queue()
5015 {
5016     hb_state_t s;
5017     hb_get_state2( h_queue, &s );
5018
5019     if( s.state == HB_STATE_PAUSED )
5020     {
5021                 hb_status.queue.state &= ~GHB_STATE_PAUSED;
5022                 hb_resume( h_queue );
5023     }
5024     else
5025     {
5026                 hb_status.queue.state |= GHB_STATE_PAUSED;
5027                 hb_pause( h_queue );
5028     }
5029 }
5030
5031 static void
5032 vert_line(
5033         GdkPixbuf * pb, 
5034         guint8 r, 
5035         guint8 g, 
5036         guint8 b, 
5037         gint x, 
5038         gint y, 
5039         gint len, 
5040         gint width)
5041 {
5042         guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5043         guint8 *dst;
5044         gint ii, jj;
5045         gint channels = gdk_pixbuf_get_n_channels (pb);
5046         gint stride = gdk_pixbuf_get_rowstride (pb);
5047
5048         for (jj = 0; jj < width; jj++)
5049         {
5050                 dst = pixels + y * stride + (x+jj) * channels;
5051                 for (ii = 0; ii < len; ii++)
5052                 {
5053                         dst[0] = r;
5054                         dst[1] = g;
5055                         dst[2] = b;
5056                         dst += stride;
5057                 }
5058         }
5059 }
5060
5061 static void
5062 horz_line(
5063         GdkPixbuf * pb, 
5064         guint8 r, 
5065         guint8 g, 
5066         guint8 b, 
5067         gint x, 
5068         gint y, 
5069         gint len,
5070         gint width)
5071 {
5072         guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5073         guint8 *dst;
5074         gint ii, jj;
5075         gint channels = gdk_pixbuf_get_n_channels (pb);
5076         gint stride = gdk_pixbuf_get_rowstride (pb);
5077
5078         for (jj = 0; jj < width; jj++)
5079         {
5080                 dst = pixels + (y+jj) * stride + x * channels;
5081                 for (ii = 0; ii < len; ii++)
5082                 {
5083                         dst[0] = r;
5084                         dst[1] = g;
5085                         dst[2] = b;
5086                         dst += channels;
5087                 }
5088         }
5089 }
5090
5091 static void
5092 hash_pixbuf(
5093         GdkPixbuf * pb,
5094         gint        x,
5095         gint        y,
5096         gint        w,
5097         gint        h,
5098         gint        step,
5099         gint            orientation)
5100 {
5101         gint ii, jj;
5102         gint line_width = 8;
5103         struct
5104         {
5105                 guint8 r;
5106                 guint8 g;
5107                 guint8 b;
5108         } c[4] = 
5109         {{0x80, 0x80, 0x80},{0xC0, 0x80, 0x70},{0x80, 0xA0, 0x80},{0x70, 0x80, 0xA0}};
5110
5111         if (!orientation)
5112         {
5113                 // vertical lines
5114                 for (ii = x, jj = 0; ii+line_width < x+w; ii += step, jj++)
5115                 {
5116                         vert_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, ii, y, h, line_width);
5117                 }
5118         }
5119         else
5120         {
5121                 // horizontal lines
5122                 for (ii = y, jj = 0; ii+line_width < y+h; ii += step, jj++)
5123                 {
5124                         horz_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, x, ii, w, line_width);
5125                 }
5126         }
5127 }
5128
5129 GdkPixbuf*
5130 ghb_get_preview_image(
5131         gint titleindex, 
5132         gint index, 
5133         signal_user_data_t *ud,
5134         gint *out_width,
5135         gint *out_height)
5136 {
5137         GValue *settings;
5138         hb_title_t *title;
5139         hb_list_t  *list;
5140         
5141         settings = ud->settings;
5142         list = hb_get_titles( h_scan );
5143         if( !hb_list_count( list ) )
5144         {
5145                 /* No valid title, stop right there */
5146                 return NULL;
5147         }
5148     title = hb_list_item( list, titleindex );
5149         if (title == NULL) return NULL;
5150         if (title->job == NULL) return NULL;
5151         set_preview_job_settings(title->job, settings);
5152
5153         // hb_get_preview doesn't compensate for anamorphic, so lets
5154         // calculate scale factors
5155         gint width, height, par_width = 1, par_height = 1;
5156         gint pic_par = ghb_settings_combo_int(settings, "PicturePAR");
5157         if (pic_par)
5158         {
5159                 hb_set_anamorphic_size( title->job, &width, &height, 
5160                                                                 &par_width, &par_height );
5161         }
5162
5163         // Make sure we have a big enough buffer to receive the image from libhb
5164         gint dstWidth = title->job->width;
5165         gint dstHeight= title->job->height;
5166
5167         static guint8 *buffer = NULL;
5168         static gint bufferSize = 0;
5169         gint newSize;
5170
5171         newSize = dstWidth * dstHeight * 4;
5172         if( bufferSize < newSize )
5173         {
5174                 bufferSize = newSize;
5175                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
5176         }
5177         hb_get_preview( h_scan, title, index, buffer );
5178
5179         // Create an GdkPixbuf and copy the libhb image into it, converting it from
5180         // libhb's format something suitable.
5181         
5182         // The image data returned by hb_get_preview is 4 bytes per pixel, 
5183         // BGRA format. Alpha is ignored.
5184
5185         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
5186         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
5187         
5188         guint32 *src = (guint32*)buffer;
5189         guint8 *dst = pixels;
5190
5191         gint ii, jj;
5192         gint channels = gdk_pixbuf_get_n_channels (preview);
5193         gint stride = gdk_pixbuf_get_rowstride (preview);
5194         guint8 *tmp;
5195
5196         for (ii = 0; ii < dstHeight; ii++)
5197         {
5198                 tmp = dst;
5199                 for (jj = 0; jj < dstWidth; jj++)
5200                 {
5201                         tmp[0] = src[0] >> 16;
5202                         tmp[1] = src[0] >> 8;
5203                         tmp[2] = src[0] >> 0;
5204                         tmp += channels;
5205                         src++;
5206                 }
5207                 dst += stride;
5208         }
5209         gint w = ghb_settings_get_int(settings, "scale_width");
5210         gint h = ghb_settings_get_int(settings, "scale_height");
5211         ghb_par_scale(ud, &w, &h, par_width, par_height);
5212
5213         gint c0, c1, c2, c3;
5214         c0 = ghb_settings_get_int(settings, "PictureTopCrop");
5215         c1 = ghb_settings_get_int(settings, "PictureBottomCrop");
5216         c2 = ghb_settings_get_int(settings, "PictureLeftCrop");
5217         c3 = ghb_settings_get_int(settings, "PictureRightCrop");
5218
5219         gdouble xscale = (gdouble)w / (gdouble)(title->width - c2 - c3);
5220         gdouble yscale = (gdouble)h / (gdouble)(title->height - c0 - c1);
5221         
5222         ghb_par_scale(ud, &dstWidth, &dstHeight, par_width, par_height);
5223         *out_width = w;
5224         *out_height = h;
5225         if (ghb_settings_get_boolean(settings, "reduce_hd_preview"))
5226         {
5227                 GdkScreen *ss;
5228                 gint s_w, s_h;
5229                 gint orig_w, orig_h;
5230                 gint factor = 80;
5231
5232                 if (ghb_settings_get_boolean(settings, "preview_fullscreen"))
5233                 {
5234                         factor = 100;
5235                 }
5236                 ss = gdk_screen_get_default();
5237                 s_w = gdk_screen_get_width(ss);
5238                 s_h = gdk_screen_get_height(ss);
5239                 orig_w = dstWidth;
5240                 orig_h = dstHeight;
5241
5242                 if (dstWidth > s_w * factor / 100)
5243                 {
5244                         dstWidth = s_w * factor / 100;
5245                         dstHeight = dstHeight * dstWidth / orig_w;
5246                 }
5247                 if (dstHeight > s_h * factor / 100)
5248                 {
5249                         dstHeight = s_h * factor / 100;
5250                         dstWidth = dstWidth * dstHeight / orig_h;
5251                 }
5252                 xscale *= (gdouble)dstWidth / orig_w;
5253                 yscale *= (gdouble)dstHeight / orig_h;
5254                 w *= (gdouble)dstWidth / orig_w;
5255                 h *= (gdouble)dstHeight / orig_h;
5256         }
5257         GdkPixbuf *scaled_preview;
5258         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
5259         if (ghb_settings_get_boolean(settings, "show_crop"))
5260         {
5261                 c0 *= yscale;
5262                 c1 *= yscale;
5263                 c2 *= xscale;
5264                 c3 *= xscale;
5265                 // Top
5266                 hash_pixbuf(scaled_preview, c2, 0, w, c0, 32, 0);
5267                 // Bottom
5268                 hash_pixbuf(scaled_preview, c2, dstHeight-c1, w, c1, 32, 0);
5269                 // Left
5270                 hash_pixbuf(scaled_preview, 0, c0, c2, h, 32, 1);
5271                 // Right
5272                 hash_pixbuf(scaled_preview, dstWidth-c3, c0, c3, h, 32, 1);
5273         }
5274         g_object_unref (preview);
5275         return scaled_preview;
5276 }
5277
5278 static void
5279 sanitize_volname(gchar *name)
5280 {
5281         gchar *a, *b;
5282
5283         a = b = name;
5284         while (*b)
5285         {
5286                 switch(*b)
5287                 {
5288                 case '<':
5289                         b++;
5290                         break;
5291                 case '>':
5292                         b++;
5293                         break;
5294                 default:
5295                         *a = *b;
5296                         a++; b++;
5297                         break;
5298                 }
5299         }
5300         *a = 0;
5301 }
5302
5303 gchar*
5304 ghb_dvd_volname(const gchar *device)
5305 {
5306         gchar *name;
5307         name = hb_dvd_name((gchar*)device);
5308         if (name != NULL && name[0] != 0)
5309         {
5310                 name = g_strdup(name);
5311                 sanitize_volname(name);
5312                 return name;
5313         }
5314         return NULL;
5315 }