OSDN Git Service

LinGui: add more informative warning about x264 RF 0 usage
[handbrake-jp/handbrake-jp-git.git] / gtk / src / hb-backend.c
1 /***************************************************************************
2  *            hb-backend.c
3  *
4  *  Fri Mar 28 10:38:44 2008
5  *  Copyright  2008  John Stebbins
6  *  <john at stebbins dot name>
7  ****************************************************************************/
8
9 /*
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Library General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
23  */
24 #define _GNU_SOURCE
25 #include <limits.h>
26 #include <math.h>
27 #include "hb.h"
28 #include <gtk/gtk.h>
29 #include <glib/gstdio.h>
30 #include "hb-backend.h"
31 #include "settings.h"
32 #include "callbacks.h"
33 #include "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         {"Blind", "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                                 titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds - %s",
1894                                         title->index, title->hours, title->minutes, title->seconds, 
1895                                         title->name);
1896                         }
1897                         else
1898                         {
1899                                 titles[ii]  = g_strdup_printf ("%d - %s", 
1900                                                                                 title->index, title->name);
1901                         }
1902                 }
1903                 else
1904                 {
1905                         if (title->duration != 0)
1906                         {
1907                                 titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds",
1908                                         title->index, title->hours, title->minutes, title->seconds);
1909                         }
1910                         else
1911                         {
1912                                 titles[ii]  = g_strdup_printf ("%d - Unknown Length", 
1913                                                                                 title->index);
1914                         }
1915                 }
1916                 gtk_list_store_append(store, &iter);
1917                 gtk_list_store_set(store, &iter, 
1918                                                    0, titles[ii], 
1919                                                    1, TRUE, 
1920                                                    2, titles[ii], 
1921                                                    3, (gdouble)ii, 
1922                                                    4, titles[ii], 
1923                                                    -1);
1924                 title_opts.map[ii].option = titles[ii];
1925                 title_opts.map[ii].shortOpt = titles[ii];
1926                 title_opts.map[ii].ivalue = ii;
1927                 title_opts.map[ii].svalue = titles[ii];
1928         }
1929         titles[ii] = NULL;
1930 }
1931
1932 static gboolean
1933 find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter)
1934 {
1935         gdouble ivalue;
1936         gboolean foundit = FALSE;
1937         
1938         if (gtk_tree_model_get_iter_first (store, iter))
1939         {
1940                 do
1941                 {
1942                         gtk_tree_model_get(store, iter, 3, &ivalue, -1);
1943                         if (value == (gint)ivalue)
1944                         {
1945                                 foundit = TRUE;
1946                                 break;
1947                         }
1948                 } while (gtk_tree_model_iter_next (store, iter));
1949         }
1950         return foundit;
1951 }
1952
1953 void
1954 audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1955 {
1956         GtkTreeIter iter;
1957         GtkListStore *store;
1958         hb_list_t  * list = NULL;
1959         hb_title_t * title = NULL;
1960     hb_audio_config_t * audio;
1961         gint ii;
1962         gint count = 0;
1963         gchar *str;
1964         
1965         g_debug("audio_track_opts_set ()\n");
1966         store = get_combo_box_store(builder, name);
1967         gtk_list_store_clear(store);
1968         if (h_scan != NULL)
1969         {
1970                 list = hb_get_titles( h_scan );
1971             title = (hb_title_t*)hb_list_item( list, titleindex );
1972                 if (title != NULL)
1973                 {
1974                         count = hb_list_count( title->list_audio );
1975                 }
1976         }
1977         if (count > 100) count = 100;
1978         if (audio_track_opts.map) g_free(audio_track_opts.map);
1979         if (count > 0)
1980         {
1981                 audio_track_opts.count = count;
1982                 audio_track_opts.map = g_malloc(count*sizeof(options_map_t));
1983         }
1984         else
1985         {
1986                 audio_track_opts.count = 1;
1987                 audio_track_opts.map = g_malloc(sizeof(options_map_t));
1988         }
1989         if( count <= 0 )
1990         {
1991                 // No audio. set some default
1992                 gtk_list_store_append(store, &iter);
1993                 gtk_list_store_set(store, &iter, 
1994                                                    0, "<small>No Audio</small>", 
1995                                                    1, TRUE, 
1996                                                    2, "none", 
1997                                                    3, -1.0, 
1998                                                    4, "none", 
1999                                                    -1);
2000                 audio_track_opts.map[0].option = "No Audio";
2001                 audio_track_opts.map[0].shortOpt = "none";
2002                 audio_track_opts.map[0].ivalue = -1;
2003                 audio_track_opts.map[0].svalue = "none";
2004                 return;
2005         }
2006         index_str_init(count-1);
2007         for (ii = 0; ii < count; ii++)
2008         {
2009         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, ii );
2010                 gtk_list_store_append(store, &iter);
2011                 str = g_strdup_printf("<small>%s</small>", audio->lang.description);
2012                 gtk_list_store_set(store, &iter, 
2013                                                    0, str,
2014                                                    1, TRUE, 
2015                                                    2, index_str[ii], 
2016                                                    3, (gdouble)ii, 
2017                                                    4, index_str[ii], 
2018                                                    -1);
2019                 g_free(str);
2020                 audio_track_opts.map[ii].option = audio->lang.description,
2021                 audio_track_opts.map[ii].shortOpt = index_str[ii];
2022                 audio_track_opts.map[ii].ivalue = ii;
2023                 audio_track_opts.map[ii].svalue = index_str[ii];
2024         }
2025 }
2026
2027 void
2028 subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
2029 {
2030         GtkTreeIter iter;
2031         GtkListStore *store;
2032         hb_list_t  * list = NULL;
2033         hb_title_t * title = NULL;
2034         hb_subtitle_t * subtitle;
2035         gint ii, count = 0;
2036         static char ** options = NULL;
2037         
2038         g_debug("subtitle_track_opts_set ()\n");
2039         store = get_combo_box_store(builder, name);
2040         gtk_list_store_clear(store);
2041         if (h_scan != NULL)
2042         {
2043                 list = hb_get_titles( h_scan );
2044             title = (hb_title_t*)hb_list_item( list, titleindex );
2045                 if (title != NULL)
2046                 {
2047                         count = hb_list_count( title->list_subtitle );
2048                 }
2049         }
2050         if (count > 100) count = 100;
2051         if (subtitle_opts.map) g_free(subtitle_opts.map);
2052         if (count > 0)
2053         {
2054                 subtitle_opts.count = count+1;
2055                 subtitle_opts.map = g_malloc((count+1)*sizeof(options_map_t));
2056         }
2057         else
2058         {
2059                 subtitle_opts.count = LANG_TABLE_SIZE+1;
2060                 subtitle_opts.map = g_malloc((LANG_TABLE_SIZE+1)*sizeof(options_map_t));
2061         }
2062         gtk_list_store_append(store, &iter);
2063         gtk_list_store_set(store, &iter, 
2064                                            0, "Foreign Audio Search", 
2065                                            1, TRUE, 
2066                                            2, "-1", 
2067                                            3, -1.0, 
2068                                            4, "auto", 
2069                                            -1);
2070         subtitle_opts.map[0].option = "Foreign Audio Search";
2071         subtitle_opts.map[0].shortOpt = "-1";
2072         subtitle_opts.map[0].ivalue = -1;
2073         subtitle_opts.map[0].svalue = "auto";
2074         if (count > 0)
2075         {
2076                 if (options != NULL)
2077                         g_strfreev(options);
2078                 options = g_malloc((count+1)*sizeof(gchar*));
2079                 index_str_init(count-1);
2080                 for (ii = 0; ii < count; ii++)
2081                 {
2082                 subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
2083                         options[ii] = g_strdup_printf("%d - %s (%s)", ii+1, 
2084                                 subtitle->lang, 
2085                                 ghb_subtitle_source_name(subtitle->source));
2086                         subtitle_opts.map[ii+1].option = options[ii];
2087                         subtitle_opts.map[ii+1].shortOpt = index_str[ii];
2088                         subtitle_opts.map[ii+1].ivalue = ii;
2089                         subtitle_opts.map[ii+1].svalue = subtitle->iso639_2;
2090                         gtk_list_store_append(store, &iter);
2091                         gtk_list_store_set(store, &iter, 
2092                                                 0, options[ii], 
2093                                                 1, TRUE, 
2094                                                 2, index_str[ii], 
2095                                                 3, (gdouble)ii, 
2096                                                 4, subtitle->iso639_2, 
2097                                                 -1);
2098                 }
2099                 options[count] = NULL;
2100         }
2101         else
2102         {
2103                 index_str_init(LANG_TABLE_SIZE-1);
2104                 for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
2105                 {
2106                         const gchar *lang;
2107
2108                         if (ghb_language_table[ii].native_name[0] != 0)
2109                                 lang = ghb_language_table[ii].native_name;
2110                         else
2111                                 lang = ghb_language_table[ii].eng_name;
2112
2113                         subtitle_opts.map[ii+1].option = lang;
2114                         subtitle_opts.map[ii+1].shortOpt = index_str[ii];
2115                         subtitle_opts.map[ii+1].ivalue = ii;
2116                         subtitle_opts.map[ii+1].svalue = ghb_language_table[ii].iso639_2;
2117                         gtk_list_store_append(store, &iter);
2118                         gtk_list_store_set(store, &iter, 
2119                                         0, lang,
2120                                         1, TRUE, 
2121                                         2, index_str[ii],
2122                                         3, (gdouble)ii, 
2123                                         4, ghb_language_table[ii].iso639_2, 
2124                                         -1);
2125                 }
2126         }
2127 }
2128
2129 gint
2130 ghb_longest_title()
2131 {
2132         hb_list_t  * list;
2133         hb_title_t * title;
2134         gint ii;
2135         gint count = 0;
2136         gint titleindex = 0;
2137         gint feature;
2138         
2139         g_debug("ghb_longest_title ()\n");
2140         if (h_scan == NULL) return 0;
2141         list = hb_get_titles( h_scan );
2142         count = hb_list_count( list );
2143         if (count > 100) count = 100;
2144         if (count < 1) return 0;
2145         title = (hb_title_t*)hb_list_item(list, 0);
2146         feature = title->job->feature;
2147         for (ii = 0; ii < count; ii++)
2148         {
2149                 title = (hb_title_t*)hb_list_item(list, ii);
2150                 if (title->index == feature)
2151                 {
2152                         return ii;
2153                 }
2154         }
2155         return titleindex;
2156 }
2157
2158 gchar*
2159 ghb_get_source_audio_lang(gint titleindex, gint track)
2160 {
2161         hb_list_t  * list;
2162         hb_title_t * title;
2163     hb_audio_config_t * audio;
2164         gchar *lang = NULL;
2165         
2166         g_debug("ghb_lookup_1st_audio_lang ()\n");
2167         if (h_scan == NULL) 
2168                 return NULL;
2169         list = hb_get_titles( h_scan );
2170     title = (hb_title_t*)hb_list_item( list, titleindex );
2171         if (title == NULL)
2172                 return NULL;
2173         if (hb_list_count( title->list_audio ) <= track)
2174                 return NULL;
2175
2176         audio = hb_list_audio_config_item(title->list_audio, track);
2177         if (audio == NULL)
2178                 return NULL;
2179
2180         lang = g_strdup(audio->lang.iso639_2);
2181         return lang;
2182 }
2183
2184 static gboolean*
2185 get_track_used(gint acodec, GHashTable *track_indices, gint count)
2186 {
2187         gboolean *used;
2188
2189         used = g_hash_table_lookup(track_indices, &acodec);
2190         if (used == NULL)
2191         {
2192                 gint *key;
2193
2194                 used = g_malloc0(count * sizeof(gboolean));
2195                 key = g_malloc(sizeof(gint));
2196                 *key = acodec;
2197                 g_hash_table_insert(track_indices, key, used);
2198         }
2199         return used;
2200 }
2201
2202 gint
2203 ghb_find_audio_track(
2204         gint titleindex, 
2205         const gchar *lang, 
2206         gint acodec,
2207         gint fallback_acodec,
2208         GHashTable *track_indices)
2209 {
2210         hb_list_t  * list;
2211         hb_title_t * title;
2212         hb_audio_config_t * audio;
2213         gint ii;
2214         gint count = 0;
2215         gint track = -1;
2216         gint max_chan;
2217         gboolean *used = NULL;
2218         gboolean *passthru_used;
2219         gint try_acodec;
2220         gint passthru_acodec;
2221         gboolean passthru;
2222         gint channels;
2223         
2224         g_debug("find_audio_track ()\n");
2225         if (h_scan == NULL) return -1;
2226         list = hb_get_titles( h_scan );
2227         title = (hb_title_t*)hb_list_item( list, titleindex );
2228         if (title != NULL)
2229         {
2230                 count = hb_list_count( title->list_audio );
2231         }
2232         if (count > 10) count = 10;
2233         // Try to find an item that matches the preferred language and
2234         // the passthru codec type
2235         max_chan = 0;
2236         passthru = (acodec & HB_ACODEC_PASS_FLAG) != 0;
2237         if (passthru)
2238         {
2239                 for (ii = 0; ii < count; ii++)
2240                 {
2241                         audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2242                                                                                                         title->list_audio, ii );
2243                         passthru_acodec = HB_ACODEC_PASS_MASK & acodec & audio->in.codec;
2244                         // Is the source track use a passthru capable codec?
2245                         if (passthru_acodec == 0)
2246                                 continue;
2247                         used = get_track_used(passthru_acodec, track_indices, count);
2248                         // Has the track already been used with this codec?
2249                         if (used[ii])
2250                                 continue;
2251
2252                         channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2253                                                                                                         audio->in.channel_layout);
2254                         // Find a track that is not visually impaired or dirctor's
2255                         // commentary, and has the highest channel count.
2256                         if ((audio->lang.type < 2) &&
2257                                 ((strcmp(lang, audio->lang.iso639_2) == 0) ||
2258                                 (strcmp(lang, "und") == 0)))
2259                         {
2260                                 if (channels > max_chan)
2261                                 {
2262                                         track = ii;
2263                                         max_chan = channels;
2264                                 }
2265                         }
2266                 }
2267                 try_acodec = fallback_acodec;
2268         }
2269         else
2270         {
2271                 try_acodec = acodec;
2272         }
2273         if (track > -1)
2274         {
2275                 used[track] = TRUE;
2276                 return track;
2277         }
2278         // Try to find an item that matches the preferred language
2279         max_chan = 0;
2280         used = get_track_used(try_acodec, track_indices, count);
2281         for (ii = 0; ii < count; ii++)
2282         {
2283                 // Has the track already been used with this codec?
2284                 if (used[ii])
2285                         continue;
2286                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2287                                                                                                 title->list_audio, ii );
2288                 passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
2289                 if (passthru_acodec && passthru)
2290                 {
2291                         passthru_used = get_track_used(passthru_acodec, track_indices, count);
2292                         // Has the track already been used with this codec for passthru?
2293                         if (passthru_used[ii])
2294                                 continue;
2295                 }
2296                 channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2297                                                                                                 audio->in.channel_layout);
2298                 // Find a track that is not visually impaired or dirctor's commentary
2299                 if ((audio->lang.type < 2) &&
2300                         ((strcmp(lang, audio->lang.iso639_2) == 0) ||
2301                         (strcmp(lang, "und") == 0)))
2302                 {
2303                         if (channels > max_chan)
2304                         {
2305                                 track = ii;
2306                                 max_chan = channels;
2307                         }
2308                 }
2309         }
2310         if (track > -1)
2311         {
2312                 used[track] = TRUE;
2313                 return track;
2314         }
2315         // Try to fine an item that does not match the preferred language and
2316         // matches the passthru codec type
2317         max_chan = 0;
2318         if (passthru)
2319         {
2320                 for (ii = 0; ii < count; ii++)
2321                 {
2322                         audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2323                                                                                                         title->list_audio, ii );
2324                         passthru_acodec = HB_ACODEC_PASS_MASK & acodec & audio->in.codec;
2325                         // Is the source track use a passthru capable codec?
2326                         if (passthru_acodec == 0)
2327                                 continue;
2328                         used = get_track_used(passthru_acodec, track_indices, count);
2329                         // Has the track already been used with this codec?
2330                         if (used[ii])
2331                                 continue;
2332
2333                         channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2334                                                                                                         audio->in.channel_layout);
2335                         // Find a track that is not visually impaired or dirctor's
2336                         // commentary, and has the highest channel count.
2337                         if (audio->lang.type < 2)
2338                         {
2339                                 if (channels > max_chan)
2340                                 {
2341                                         track = ii;
2342                                         max_chan = channels;
2343                                 }
2344                         }
2345                 }
2346                 try_acodec = fallback_acodec;
2347         }
2348         else
2349         {
2350                 try_acodec = acodec;
2351         }
2352         if (track > -1)
2353         {
2354                 used[track] = TRUE;
2355                 return track;
2356         }
2357         // Try to fine an item that does not match the preferred language
2358         max_chan = 0;
2359         used = get_track_used(try_acodec, track_indices, count);
2360         for (ii = 0; ii < count; ii++)
2361         {
2362                 // Has the track already been used with this codec?
2363                 if (used[ii])
2364                         continue;
2365                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2366                                                                                                         title->list_audio, ii );
2367                 passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
2368                 channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
2369                                                                                                 audio->in.channel_layout);
2370                 if (passthru_acodec && passthru)
2371                 {
2372                         passthru_used = get_track_used(passthru_acodec, track_indices, count);
2373                         // Has the track already been used with this codec for passthru?
2374                         if (passthru_used[ii])
2375                                 continue;
2376                 }
2377                 // Find a track that is not visually impaired or dirctor's commentary
2378                 if (audio->lang.type < 2)
2379                 {
2380                         if (channels > max_chan)
2381                         {
2382                                 track = ii;
2383                                 max_chan = channels;
2384                         }
2385                 }
2386         }
2387         if (track > -1)
2388         {
2389                 used[track] = TRUE;
2390                 return track;
2391         }
2392         // Last ditch, anything goes
2393         for (ii = 0; ii < count; ii++)
2394         {
2395                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
2396                                                                                                 title->list_audio, ii );
2397                 passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
2398                 if (passthru_acodec && passthru)
2399                 {
2400                         passthru_used = get_track_used(passthru_acodec, track_indices, count);
2401                         // Has the track already been used with this codec for passthru?
2402                         if (passthru_used[ii])
2403                                 continue;
2404                 }
2405                 // Has the track already been used with this codec?
2406                 if (!used[ii])
2407                 {
2408                         track = ii;
2409                         break;
2410                 }
2411         }
2412         if (track > -1)
2413         {
2414                 used[track] = TRUE;
2415         }
2416         return track;
2417 }
2418
2419 gint
2420 ghb_find_pref_subtitle_track(const gchar *lang)
2421 {
2422         gint ii, count;
2423         count = subtitle_opts.count;
2424         for (ii = 0; ii < count; ii++)
2425         {
2426                 if (strcmp(lang, subtitle_opts.map[ii].svalue) == 0)
2427                 {
2428                         return subtitle_opts.map[ii].ivalue;
2429                 }
2430         }
2431         return -2;
2432 }
2433
2434 gint
2435 ghb_find_cc_track(gint titleindex)
2436 {
2437         hb_list_t  * list;
2438         hb_title_t * title;
2439         hb_subtitle_t * subtitle;
2440         gint count, ii;
2441         
2442         g_debug("ghb_find_cc_track ()\n");
2443         if (h_scan == NULL) return -2;
2444         list = hb_get_titles( h_scan );
2445         title = (hb_title_t*)hb_list_item( list, titleindex );
2446         if (title != NULL)
2447         {
2448                 count = hb_list_count( title->list_subtitle );
2449                 // Try to find an item that matches the preferred language
2450                 for (ii = 0; ii < count; ii++)
2451                 {
2452                 subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
2453                         if (subtitle->source == CC608SUB || subtitle->source == CC708SUB)
2454                                 return ii;
2455                 }
2456         }
2457         return -2;
2458 }
2459
2460 static gboolean
2461 canForce(int source)
2462 {
2463         return (source == VOBSUB);
2464 }
2465
2466 static gboolean
2467 canBurn(int source)
2468 {
2469         return (source == VOBSUB || source == SSASUB);
2470 }
2471
2472 gint
2473 ghb_find_subtitle_track(
2474         gint          titleindex, 
2475         const gchar * lang, 
2476         gboolean      burn,
2477         gboolean      force,
2478         gint          source,
2479         GHashTable  * track_indices)
2480 {
2481         hb_list_t  * list;
2482         hb_title_t * title;
2483         hb_subtitle_t * subtitle;
2484         gint count, ii;
2485         gboolean *used;
2486         
2487         g_debug("find_subtitle_track ()\n");
2488         if (strcmp(lang, "auto") == 0)
2489                 return -1;
2490         if (h_scan == NULL) return -1;
2491         list = hb_get_titles( h_scan );
2492         title = (hb_title_t*)hb_list_item( list, titleindex );
2493         if (title != NULL)
2494         {
2495                 count = hb_list_count( title->list_subtitle );
2496                 used = g_hash_table_lookup(track_indices, lang);
2497                 if (used == NULL)
2498                 {
2499                         used = g_malloc0(count * sizeof(gboolean));
2500                         g_hash_table_insert(track_indices, g_strdup(lang), used);
2501                 }
2502                 // Try to find an item that matches the preferred language and source
2503                 for (ii = 0; ii < count; ii++)
2504                 {
2505                         if (used[ii])
2506                                 continue;
2507
2508                 subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
2509                         if (source == subtitle->source &&
2510                                 ((strcmp(lang, subtitle->iso639_2) == 0) ||
2511                                  (strcmp(lang, "und") == 0)))
2512                         {
2513                                 used[ii] = TRUE;
2514                                 return ii;
2515                         }
2516                 }
2517                 // Try to find an item that matches the preferred language
2518                 for (ii = 0; ii < count; ii++)
2519                 {
2520                         if (used[ii])
2521                                 continue;
2522
2523                 subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
2524                         if (((!force || (force && canForce(subtitle->source))) &&
2525                                  (!burn  || (burn  &&  canBurn(subtitle->source)))) &&
2526                                 ((strcmp(lang, subtitle->iso639_2) == 0) ||
2527                                  (strcmp(lang, "und") == 0)))
2528                         {
2529                                 used[ii] = TRUE;
2530                                 return ii;
2531                         }
2532                 }
2533         }
2534         return -2;
2535 }
2536
2537 static void
2538 generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
2539 {
2540         GtkTreeIter iter;
2541         GtkListStore *store;
2542         gint ii;
2543         
2544         g_debug("generic_opts_set ()\n");
2545         if (name == NULL || opts == NULL) return;
2546         store = get_combo_box_store(builder, name);
2547         gtk_list_store_clear(store);
2548         for (ii = 0; ii < opts->count; ii++)
2549         {
2550                 gtk_list_store_append(store, &iter);
2551                 gtk_list_store_set(store, &iter, 
2552                                                    0, opts->map[ii].option, 
2553                                                    1, TRUE, 
2554                                                    2, opts->map[ii].shortOpt, 
2555                                                    3, opts->map[ii].ivalue, 
2556                                                    4, opts->map[ii].svalue, 
2557                                                    -1);
2558         }
2559 }
2560
2561 static void
2562 small_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
2563 {
2564         GtkTreeIter iter;
2565         GtkListStore *store;
2566         gint ii;
2567         gchar *str;
2568         
2569         g_debug("small_opts_set ()\n");
2570         if (name == NULL || opts == NULL) return;
2571         store = get_combo_box_store(builder, name);
2572         gtk_list_store_clear(store);
2573         for (ii = 0; ii < opts->count; ii++)
2574         {
2575                 gtk_list_store_append(store, &iter);
2576                 str = g_strdup_printf("<small>%s</small>", opts->map[ii].option);
2577                 gtk_list_store_set(store, &iter, 
2578                                                    0, str,
2579                                                    1, TRUE, 
2580                                                    2, opts->map[ii].shortOpt, 
2581                                                    3, opts->map[ii].ivalue, 
2582                                                    4, opts->map[ii].svalue, 
2583                                                    -1);
2584                 g_free(str);
2585         }
2586 }
2587
2588 combo_opts_t*
2589 find_combo_table(const gchar *name)
2590 {
2591         gint ii;
2592
2593         for (ii = 0; combo_name_map[ii].name != NULL; ii++)
2594         {
2595                 if (strcmp(name, combo_name_map[ii].name) == 0)
2596                 {
2597                         return combo_name_map[ii].opts;
2598                 }
2599         }
2600         return NULL;
2601 }
2602
2603 gint
2604 ghb_lookup_combo_int(const gchar *name, const GValue *gval)
2605 {
2606         if (gval == NULL)
2607                 return 0;
2608         if (strcmp(name, "AudioBitrate") == 0)
2609                 return lookup_audio_bitrate_int(gval);
2610         else if (strcmp(name, "AudioSamplerate") == 0)
2611                 return lookup_audio_rate_int(gval);
2612         else if (strcmp(name, "VideoFramerate") == 0)
2613                 return lookup_video_rate_int(gval);
2614         else if (strcmp(name, "AudioMixdown") == 0)
2615                 return lookup_mix_int(gval);
2616         else if (strcmp(name, "SrtLanguage") == 0)
2617                 return lookup_audio_lang_int(gval);
2618         else if (strcmp(name, "PreferredLanguage") == 0)
2619                 return lookup_audio_lang_int(gval);
2620         else
2621         {
2622                 return lookup_generic_int(find_combo_table(name), gval);
2623         }
2624         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2625         return 0;
2626 }
2627
2628 gdouble
2629 ghb_lookup_combo_double(const gchar *name, const GValue *gval)
2630 {
2631         if (gval == NULL)
2632                 return 0;
2633         if (strcmp(name, "AudioBitrate") == 0)
2634                 return lookup_audio_bitrate_int(gval);
2635         else if (strcmp(name, "AudioSamplerate") == 0)
2636                 return lookup_audio_rate_int(gval);
2637         else if (strcmp(name, "VideoFramerate") == 0)
2638                 return lookup_video_rate_int(gval);
2639         else if (strcmp(name, "AudioMixdown") == 0)
2640                 return lookup_mix_int(gval);
2641         else if (strcmp(name, "SrtLanguage") == 0)
2642                 return lookup_audio_lang_int(gval);
2643         else if (strcmp(name, "PreferredLanguage") == 0)
2644                 return lookup_audio_lang_int(gval);
2645         else
2646         {
2647                 return lookup_generic_double(find_combo_table(name), gval);
2648         }
2649         g_warning("ghb_lookup_combo_double() couldn't find %s", name);
2650         return 0;
2651 }
2652
2653 const gchar*
2654 ghb_lookup_combo_option(const gchar *name, const GValue *gval)
2655 {
2656         if (gval == NULL)
2657                 return NULL;
2658         if (strcmp(name, "AudioBitrate") == 0)
2659                 return lookup_audio_bitrate_option(gval);
2660         else if (strcmp(name, "AudioSamplerate") == 0)
2661                 return lookup_audio_rate_option(gval);
2662         else if (strcmp(name, "VideoFramerate") == 0)
2663                 return lookup_video_rate_option(gval);
2664         else if (strcmp(name, "AudioMixdown") == 0)
2665                 return lookup_mix_option(gval);
2666         else if (strcmp(name, "SrtLanguage") == 0)
2667                 return lookup_audio_lang_option(gval);
2668         else if (strcmp(name, "PreferredLanguage") == 0)
2669                 return lookup_audio_lang_option(gval);
2670         else
2671         {
2672                 return lookup_generic_option(find_combo_table(name), gval);
2673         }
2674         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2675         return NULL;
2676 }
2677
2678 const gchar*
2679 ghb_lookup_combo_string(const gchar *name, const GValue *gval)
2680 {
2681         if (gval == NULL)
2682                 return NULL;
2683         if (strcmp(name, "AudioBitrate") == 0)
2684                 return lookup_audio_bitrate_option(gval);
2685         else if (strcmp(name, "AudioSamplerate") == 0)
2686                 return lookup_audio_rate_option(gval);
2687         else if (strcmp(name, "VideoFramerate") == 0)
2688                 return lookup_video_rate_option(gval);
2689         else if (strcmp(name, "AudioMixdown") == 0)
2690                 return lookup_mix_string(gval);
2691         else if (strcmp(name, "SrtLanguage") == 0)
2692                 return lookup_audio_lang_option(gval);
2693         else if (strcmp(name, "PreferredLanguage") == 0)
2694                 return lookup_audio_lang_option(gval);
2695         else
2696         {
2697                 return lookup_generic_string(find_combo_table(name), gval);
2698         }
2699         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2700         return NULL;
2701 }
2702
2703 void
2704 ghb_update_ui_combo_box(
2705         signal_user_data_t *ud, 
2706         const gchar *name, 
2707         gint user_data, 
2708         gboolean all)
2709 {
2710         GtkComboBox *combo = NULL;
2711         gint signal_id;
2712         gint handler_id = 0;
2713
2714         if (name != NULL)
2715         {               
2716                 g_debug("ghb_update_ui_combo_box() %s\n", name);
2717                 // Clearing a combo box causes a rash of "changed" events, even when
2718                 // the active item is -1 (inactive).  To control things, I'm disabling
2719                 // the event till things are settled down.
2720                 combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
2721                 signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX);
2722                 if (signal_id > 0)
2723                 {
2724                         // Valid signal id found.  This should always succeed.
2725                         handler_id = g_signal_handler_find ((gpointer)combo, G_SIGNAL_MATCH_ID, 
2726                                                                                                 signal_id, 0, 0, 0, 0);
2727                         if (handler_id > 0)
2728                         {
2729                                 // This should also always succeed
2730                                 g_signal_handler_block ((gpointer)combo, handler_id);
2731                         }
2732                 }
2733         }       
2734         if (all)
2735         {
2736                 audio_bitrate_opts_set(ud->builder, "AudioBitrate");
2737                 audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
2738                 video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
2739                 mix_opts_set(ud->builder, "AudioMixdown");
2740                 language_opts_set(ud->builder, "SrtLanguage");
2741                 language_opts_set(ud->builder, "PreferredLanguage");
2742                 srt_codeset_opts_set(ud->builder, "SrtCodeset");
2743                 title_opts_set(ud->builder, "title");
2744                 audio_track_opts_set(ud->builder, "AudioTrack", user_data);
2745                 subtitle_track_opts_set(ud->builder, "SubtitleTrack", user_data);
2746                 generic_opts_set(ud->builder, "VideoQualityGranularity", &vqual_granularity_opts);
2747                 generic_opts_set(ud->builder, "PtoPType", &point_to_point_opts);
2748                 generic_opts_set(ud->builder, "WhenComplete", &when_complete_opts);
2749                 generic_opts_set(ud->builder, "PicturePAR", &par_opts);
2750                 generic_opts_set(ud->builder, "PictureModulus", &alignment_opts);
2751                 generic_opts_set(ud->builder, "LoggingLevel", &logging_opts);
2752                 generic_opts_set(ud->builder, "LogLongevity", &log_longevity_opts);
2753                 generic_opts_set(ud->builder, "check_updates", &appcast_update_opts);
2754                 generic_opts_set(ud->builder, "FileFormat", &container_opts);
2755                 generic_opts_set(ud->builder, "PictureDeinterlace", &deint_opts);
2756                 generic_opts_set(ud->builder, "PictureDetelecine", &detel_opts);
2757                 generic_opts_set(ud->builder, "PictureDecomb", &decomb_opts);
2758                 generic_opts_set(ud->builder, "PictureDenoise", &denoise_opts);
2759                 generic_opts_set(ud->builder, "VideoEncoder", &vcodec_opts);
2760                 small_opts_set(ud->builder, "AudioEncoder", &acodec_opts);
2761                 small_opts_set(ud->builder, "x264_direct", &direct_opts);
2762                 small_opts_set(ud->builder, "x264_b_adapt", &badapt_opts);
2763                 small_opts_set(ud->builder, "x264_bpyramid", &bpyramid_opts);
2764                 small_opts_set(ud->builder, "x264_weighted_pframes", &weightp_opts);
2765                 small_opts_set(ud->builder, "x264_me", &me_opts);
2766                 small_opts_set(ud->builder, "x264_subme", &subme_opts);
2767                 small_opts_set(ud->builder, "x264_analyse", &analyse_opts);
2768                 small_opts_set(ud->builder, "x264_trellis", &trellis_opts);
2769         }
2770         else
2771         {
2772                 if (strcmp(name, "AudioBitrate") == 0)
2773                         audio_bitrate_opts_set(ud->builder, "AudioBitrate");
2774                 else if (strcmp(name, "AudioSamplerate") == 0)
2775                         audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
2776                 else if (strcmp(name, "VideoFramerate") == 0)
2777                         video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
2778                 else if (strcmp(name, "AudioMixdown") == 0)
2779                         mix_opts_set(ud->builder, "AudioMixdown");
2780                 else if (strcmp(name, "SrtLanguage") == 0)
2781                         language_opts_set(ud->builder, "SrtLanguage");
2782                 else if (strcmp(name, "PreferredLanguage") == 0)
2783                         language_opts_set(ud->builder, "PreferredLanguage");
2784                 else if (strcmp(name, "SrtCodeset") == 0)
2785                         srt_codeset_opts_set(ud->builder, "SrtCodeset");
2786                 else if (strcmp(name, "title") == 0)
2787                         title_opts_set(ud->builder, "title");
2788                 else if (strcmp(name, "SubtitleTrack") == 0)
2789                         subtitle_track_opts_set(ud->builder, "SubtitleTrack", user_data);
2790                 else if (strcmp(name, "AudioTrack") == 0)
2791                         audio_track_opts_set(ud->builder, "AudioTrack", user_data);
2792                 else
2793                         generic_opts_set(ud->builder, name, find_combo_table(name));
2794         }
2795         if (handler_id > 0)
2796         {
2797                 g_signal_handler_unblock ((gpointer)combo, handler_id);
2798         }
2799 }
2800         
2801 static void
2802 init_ui_combo_boxes(GtkBuilder *builder)
2803 {
2804         gint ii;
2805
2806         init_combo_box(builder, "AudioBitrate");
2807         init_combo_box(builder, "AudioSamplerate");
2808         init_combo_box(builder, "VideoFramerate");
2809         init_combo_box(builder, "AudioMixdown");
2810         init_combo_box(builder, "SrtLanguage");
2811         init_combo_box(builder, "PreferredLanguage");
2812         init_combo_box(builder, "SrtCodeset");
2813         init_combo_box(builder, "title");
2814         init_combo_box(builder, "AudioTrack");
2815         for (ii = 0; combo_name_map[ii].name != NULL; ii++)
2816         {
2817                 init_combo_box(builder, combo_name_map[ii].name);
2818         }
2819 }
2820         
2821 static const char * turbo_opts = 
2822         "ref=1:subme=2:me=dia:analyse=none:trellis=0:"
2823         "no-fast-pskip=0:8x8dct=0";
2824
2825 // Construct the x264 options string
2826 // The result is allocated, so someone must free it at some point.
2827 gchar*
2828 ghb_build_x264opts_string(GValue *settings)
2829 {
2830         gchar *result;
2831         gchar *opts = ghb_settings_get_string(settings, "x264Option");
2832         if (opts != NULL)
2833         {
2834                 result = opts;
2835         }
2836         else
2837         {
2838                 result = g_strdup("");
2839         }
2840         return result;
2841 }
2842
2843 void
2844 ghb_part_duration(gint tt, gint sc, gint ec, gint *hh, gint *mm, gint *ss)
2845 {
2846         hb_list_t  * list;
2847         hb_title_t * title;
2848     hb_chapter_t * chapter;
2849         gint count, c;
2850         gint64 duration;
2851         
2852         *hh = *mm = *ss = 0;
2853         if (h_scan == NULL) return;
2854         list = hb_get_titles( h_scan );
2855     title = (hb_title_t*)hb_list_item( list, tt );
2856         if (title == NULL) return;
2857
2858         *hh = title->hours;
2859         *mm = title->minutes;
2860         *ss = title->seconds;
2861
2862         count = hb_list_count(title->list_chapter);
2863         if (sc > count) sc = count;
2864         if (ec > count) ec = count;
2865
2866         if (sc == 1 && ec == count)
2867                 return;
2868
2869         duration = 0;
2870         for (c = sc; c <= ec; c++)
2871         {
2872                 chapter = hb_list_item(title->list_chapter, c-1);
2873                 duration += chapter->duration;
2874         }
2875
2876         *hh =   duration / 90000 / 3600;
2877         *mm = ((duration / 90000) % 3600) / 60;
2878         *ss =  (duration / 90000) % 60;
2879 }
2880
2881 void
2882 ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss)
2883 {
2884         hb_list_t  * list;
2885         hb_title_t * title;
2886     hb_chapter_t * chapter;
2887         gint count;
2888         
2889         g_debug("ghb_get_chapter_duration (title = %d)\n", ti);
2890         *hh = *mm = *ss = 0;
2891         if (h_scan == NULL) return;
2892         list = hb_get_titles( h_scan );
2893     title = (hb_title_t*)hb_list_item( list, ti );
2894         if (title == NULL) return;
2895         count = hb_list_count( title->list_chapter );
2896         if (ii >= count) return;
2897         chapter = hb_list_item(title->list_chapter, ii);
2898         if (chapter == NULL) return;
2899         *hh = chapter->hours;
2900         *mm = chapter->minutes;
2901         *ss = chapter->seconds;
2902 }
2903
2904 GValue*
2905 ghb_get_chapters(gint titleindex)
2906 {
2907         hb_list_t  * list;
2908         hb_title_t * title;
2909     hb_chapter_t * chapter;
2910         gint count, ii;
2911         GValue *chapters = NULL;
2912         
2913         g_debug("ghb_get_chapters (title = %d)\n", titleindex);
2914         if (h_scan == NULL) return NULL;
2915         list = hb_get_titles( h_scan );
2916     title = (hb_title_t*)hb_list_item( list, titleindex );
2917         if (title == NULL) return NULL;
2918         count = hb_list_count( title->list_chapter );
2919         chapters = ghb_array_value_new(count);
2920         for (ii = 0; ii < count; ii++)
2921         {
2922                 chapter = hb_list_item(title->list_chapter, ii);
2923                 if (chapter == NULL) break;
2924                 if (chapter->title == NULL || chapter->title[0] == 0)
2925                 {
2926                         gchar *str;
2927                         str = g_strdup_printf ("Chapter %2d", ii+1);
2928                         ghb_array_append(chapters, ghb_string_value_new(str));
2929                         g_free(str);
2930                 }
2931                 else 
2932                 {
2933                         ghb_array_append(chapters, ghb_string_value_new(chapter->title));
2934                 }
2935         }
2936         return chapters;
2937 }
2938
2939 gboolean
2940 ghb_ac3_in_audio_list(const GValue *audio_list)
2941 {
2942         gint count, ii;
2943
2944         count = ghb_array_len(audio_list);
2945         for (ii = 0; ii < count; ii++)
2946         {
2947                 GValue *asettings;
2948                 gint acodec;
2949
2950                 asettings = ghb_array_get_nth(audio_list, ii);
2951                 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
2952                 if (acodec & HB_ACODEC_AC3)
2953                         return TRUE;
2954         }
2955         return FALSE;
2956 }
2957
2958 static void
2959 audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
2960 {
2961         GtkTreeIter iter;
2962         GtkListStore *store;
2963         gchar *str;
2964         
2965         g_debug("audio_bitrate_opts_add ()\n");
2966
2967         if (rate < 8) return;
2968
2969         if (ghb_audio_bitrates[hb_audio_bitrates_count].string)
2970         {
2971                 g_free(ghb_audio_bitrates[hb_audio_bitrates_count].string);
2972         }
2973         ghb_audio_bitrates[hb_audio_bitrates_count].rate = rate;
2974         ghb_audio_bitrates[hb_audio_bitrates_count].string = 
2975                 g_strdup_printf("%d", rate);
2976         ghb_audio_bitrates_count = hb_audio_bitrates_count + 1;
2977
2978         store = get_combo_box_store(builder, name);
2979         if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
2980         {
2981                 str = g_strdup_printf ("<small>%d</small>", rate);
2982                 gtk_list_store_append(store, &iter);
2983                 gtk_list_store_set(store, &iter, 
2984                                                    0, str, 
2985                                                    1, TRUE, 
2986                                                    2, ghb_audio_bitrates[hb_audio_bitrates_count].string, 
2987                                                    3, (gdouble)rate, 
2988                                                    4, ghb_audio_bitrates[hb_audio_bitrates_count].string, 
2989                                                    -1);
2990                 g_free(str);
2991         }
2992 }
2993
2994 static void
2995 audio_bitrate_opts_clean(
2996         GtkBuilder *builder, 
2997         const gchar *name, 
2998         gint first_rate, 
2999         gint last_rate)
3000 {
3001         GtkTreeIter iter;
3002         GtkListStore *store;
3003         gdouble ivalue;
3004         gboolean done = FALSE;
3005         gint ii = 0;
3006         guint last = (guint)last_rate;
3007         guint first = (guint)first_rate;
3008         
3009         ghb_audio_bitrates_count = hb_audio_bitrates_count;
3010
3011         g_debug("audio_bitrate_opts_clean ()\n");
3012         store = get_combo_box_store(builder, name);
3013         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
3014         {
3015                 do
3016                 {
3017                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
3018                         if (search_rates(
3019                                 ghb_audio_bitrates, ivalue, ghb_audio_bitrates_count) < 0)
3020                         {
3021                                 done = !gtk_list_store_remove(store, &iter);
3022                         }
3023                         else if (ivalue < first || ivalue > last)
3024                         {
3025                                 ii++;
3026                                 gtk_list_store_set(store, &iter, 1, FALSE, -1);
3027                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
3028                         }
3029                         else
3030                         {
3031                                 ii++;
3032                                 gtk_list_store_set(store, &iter, 1, TRUE, -1);
3033                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
3034                         }
3035                 } while (!done);
3036         }
3037 }
3038
3039 static void
3040 audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
3041 {
3042         GtkTreeIter iter;
3043         GtkListStore *store;
3044         gint ii;
3045         gchar *str;
3046         
3047         ghb_audio_bitrates_count = hb_audio_bitrates_count;
3048         ghb_audio_bitrates = calloc(hb_audio_bitrates_count+1, sizeof(hb_rate_t));
3049
3050         for (ii = 0; ii < hb_audio_bitrates_count; ii++)
3051         {
3052                 ghb_audio_bitrates[ii] = hb_audio_bitrates[ii];
3053         }
3054
3055         g_debug("audio_bitrate_opts_set ()\n");
3056         store = get_combo_box_store(builder, name);
3057         gtk_list_store_clear(store);
3058         for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
3059         {
3060                 gtk_list_store_append(store, &iter);
3061                 str = g_strdup_printf ("<small>%s</small>", 
3062                         ghb_audio_bitrates[ii].string);
3063                 gtk_list_store_set(store, &iter, 
3064                                                    0, str,
3065                                                    1, TRUE, 
3066                                                    2, ghb_audio_bitrates[ii].string, 
3067                                                    3, (gdouble)ghb_audio_bitrates[ii].rate, 
3068                                                    4, ghb_audio_bitrates[ii].string, 
3069                                                    -1);
3070                 g_free(str);
3071         }
3072 }
3073
3074 void
3075 ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate)
3076 {
3077         audio_bitrate_opts_add(builder, "AudioBitrate", bitrate);
3078 }
3079
3080 void
3081 ghb_set_default_bitrate_opts(
3082         GtkBuilder *builder, 
3083         gint first_rate, 
3084         gint last_rate)
3085 {
3086         audio_bitrate_opts_clean(builder, "AudioBitrate", first_rate, last_rate);
3087 }
3088
3089 static ghb_status_t hb_status;
3090
3091 void
3092 ghb_combo_init(signal_user_data_t *ud)
3093 {
3094         // Set up the list model for the combos
3095         init_ui_combo_boxes(ud->builder);
3096         // Populate all the combos
3097         ghb_update_ui_combo_box(ud, NULL, 0, TRUE);
3098 }
3099
3100 void
3101 ghb_backend_init(gint debug)
3102 {
3103     /* Init libhb */
3104     h_scan = hb_init( debug, 0 );
3105     h_queue = hb_init( debug, 0 );
3106 }
3107
3108 void
3109 ghb_backend_close()
3110 {
3111         hb_close(&h_queue);
3112         hb_close(&h_scan);
3113         hb_global_close();
3114 }
3115
3116 void ghb_backend_scan_stop()
3117 {
3118     hb_scan_stop( h_scan );
3119 }
3120
3121 void
3122 ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count, uint64_t min_duration)
3123 {
3124     hb_scan( h_scan, path, titleindex, preview_count, 1, min_duration );
3125         hb_status.scan.state |= GHB_STATE_SCANNING;
3126         // initialize count and cur to something that won't cause FPE
3127         // when computing progress
3128         hb_status.scan.title_count = 1;
3129         hb_status.scan.title_cur = 0;
3130 }
3131
3132 void
3133 ghb_backend_queue_scan(const gchar *path, gint titlenum)
3134 {
3135         g_debug("ghb_backend_queue_scan()");
3136         hb_scan( h_queue, path, titlenum, 10, 0, 0 );
3137         hb_status.queue.state |= GHB_STATE_SCANNING;
3138 }
3139
3140 gint
3141 ghb_get_scan_state()
3142 {
3143         return hb_status.scan.state;
3144 }
3145
3146 gint
3147 ghb_get_queue_state()
3148 {
3149         return hb_status.queue.state;
3150 }
3151
3152 void
3153 ghb_clear_scan_state(gint state)
3154 {
3155         hb_status.scan.state &= ~state;
3156 }
3157
3158 void
3159 ghb_clear_queue_state(gint state)
3160 {
3161         hb_status.queue.state &= ~state;
3162 }
3163
3164 void
3165 ghb_set_scan_state(gint state)
3166 {
3167         hb_status.scan.state |= state;
3168 }
3169
3170 void
3171 ghb_set_queue_state(gint state)
3172 {
3173         hb_status.queue.state |= state;
3174 }
3175
3176 void
3177 ghb_get_status(ghb_status_t *status)
3178 {
3179         memcpy(status, &hb_status, sizeof(ghb_status_t));
3180 }
3181
3182 void 
3183 ghb_track_status()
3184 {
3185     hb_state_t s_scan;
3186     hb_state_t s_queue;
3187
3188         if (h_scan == NULL) return;
3189     hb_get_state( h_scan, &s_scan );
3190         switch( s_scan.state )
3191     {
3192 #define p s_scan.param.scanning
3193         case HB_STATE_SCANNING:
3194                 {
3195                         hb_status.scan.state |= GHB_STATE_SCANNING;
3196                         hb_status.scan.title_count = p.title_count;
3197                         hb_status.scan.title_cur = p.title_cur;
3198                 } break;
3199 #undef p
3200
3201         case HB_STATE_SCANDONE:
3202         {
3203                         hb_status.scan.state &= ~GHB_STATE_SCANNING;
3204                         hb_status.scan.state |= GHB_STATE_SCANDONE;
3205         } break;
3206
3207 #define p s_scan.param.working
3208         case HB_STATE_WORKING:
3209                         hb_status.scan.state |= GHB_STATE_WORKING;
3210                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
3211                         hb_status.scan.job_cur = p.job_cur;
3212                         hb_status.scan.job_count = p.job_count;
3213                         hb_status.scan.progress = p.progress;
3214                         hb_status.scan.rate_cur = p.rate_cur;
3215                         hb_status.scan.rate_avg = p.rate_avg;
3216                         hb_status.scan.hours = p.hours;
3217                         hb_status.scan.minutes = p.minutes;
3218                         hb_status.scan.seconds = p.seconds;
3219                         hb_status.scan.unique_id = p.sequence_id & 0xFFFFFF;
3220             break;
3221 #undef p
3222
3223         case HB_STATE_PAUSED:
3224                         hb_status.scan.state |= GHB_STATE_PAUSED;
3225             break;
3226                                 
3227         case HB_STATE_MUXING:
3228         {
3229                         hb_status.scan.state |= GHB_STATE_MUXING;
3230         } break;
3231
3232 #define p s_scan.param.workdone
3233         case HB_STATE_WORKDONE:
3234                 {
3235             hb_job_t *job;
3236
3237                         hb_status.scan.state |= GHB_STATE_WORKDONE;
3238                         hb_status.scan.state &= ~GHB_STATE_MUXING;
3239                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
3240                         hb_status.scan.state &= ~GHB_STATE_WORKING;
3241                         switch (p.error)
3242                         {
3243                         case HB_ERROR_NONE:
3244                                 hb_status.scan.error = GHB_ERROR_NONE;
3245                                 break;
3246                         case HB_ERROR_CANCELED:
3247                                 hb_status.scan.error = GHB_ERROR_CANCELED;
3248                                 break;
3249                         default:
3250                                 hb_status.scan.error = GHB_ERROR_FAIL;
3251                                 break;
3252                         }
3253                         // Delete all remaining jobs of this encode.
3254                         // An encode can be composed of multiple associated jobs.
3255                         // When a job is stopped, libhb removes it from the job list,
3256                         // but does not remove other jobs that may be associated with it.
3257                         // Associated jobs are taged in the sequence id.
3258             while ((job = hb_job(h_scan, 0)) != NULL) 
3259                 hb_rem( h_scan, job );
3260                 } break;
3261 #undef p
3262     }
3263     hb_get_state( h_queue, &s_queue );
3264         switch( s_queue.state )
3265     {
3266 #define p s_queue.param.scanning
3267         case HB_STATE_SCANNING:
3268                 {
3269                         hb_status.queue.state |= GHB_STATE_SCANNING;
3270                         hb_status.queue.title_count = p.title_count;
3271                         hb_status.queue.title_cur = p.title_cur;
3272                 } break;
3273 #undef p
3274
3275         case HB_STATE_SCANDONE:
3276         {
3277                         hb_status.queue.state &= ~GHB_STATE_SCANNING;
3278                         hb_status.queue.state |= GHB_STATE_SCANDONE;
3279         } break;
3280
3281 #define p s_queue.param.working
3282         case HB_STATE_WORKING:
3283                         hb_status.queue.state |= GHB_STATE_WORKING;
3284                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
3285                         hb_status.queue.state &= ~GHB_STATE_SEARCHING;
3286                         hb_status.queue.job_cur = p.job_cur;
3287                         hb_status.queue.job_count = p.job_count;
3288                         hb_status.queue.progress = p.progress;
3289                         hb_status.queue.rate_cur = p.rate_cur;
3290                         hb_status.queue.rate_avg = p.rate_avg;
3291                         hb_status.queue.hours = p.hours;
3292                         hb_status.queue.minutes = p.minutes;
3293                         hb_status.queue.seconds = p.seconds;
3294                         hb_status.queue.unique_id = p.sequence_id & 0xFFFFFF;
3295             break;
3296
3297         case HB_STATE_SEARCHING:
3298                         hb_status.queue.state |= GHB_STATE_SEARCHING;
3299                         hb_status.queue.state &= ~GHB_STATE_WORKING;
3300                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
3301                         hb_status.queue.job_cur = p.job_cur;
3302                         hb_status.queue.job_count = p.job_count;
3303                         hb_status.queue.progress = p.progress;
3304                         hb_status.queue.rate_cur = p.rate_cur;
3305                         hb_status.queue.rate_avg = p.rate_avg;
3306                         hb_status.queue.hours = p.hours;
3307                         hb_status.queue.minutes = p.minutes;
3308                         hb_status.queue.seconds = p.seconds;
3309                         hb_status.queue.unique_id = p.sequence_id & 0xFFFFFF;
3310             break;
3311 #undef p
3312
3313         case HB_STATE_PAUSED:
3314                         hb_status.queue.state |= GHB_STATE_PAUSED;
3315             break;
3316                                 
3317         case HB_STATE_MUXING:
3318         {
3319                         hb_status.queue.state |= GHB_STATE_MUXING;
3320         } break;
3321
3322 #define p s_queue.param.workdone
3323         case HB_STATE_WORKDONE:
3324                 {
3325             hb_job_t *job;
3326
3327                         hb_status.queue.state |= GHB_STATE_WORKDONE;
3328                         hb_status.queue.state &= ~GHB_STATE_MUXING;
3329                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
3330                         hb_status.queue.state &= ~GHB_STATE_WORKING;
3331                         hb_status.queue.state &= ~GHB_STATE_SEARCHING;
3332                         switch (p.error)
3333                         {
3334                         case HB_ERROR_NONE:
3335                                 hb_status.queue.error = GHB_ERROR_NONE;
3336                                 break;
3337                         case HB_ERROR_CANCELED:
3338                                 hb_status.queue.error = GHB_ERROR_CANCELED;
3339                                 break;
3340                         default:
3341                                 hb_status.queue.error = GHB_ERROR_FAIL;
3342                                 break;
3343                         }
3344                         // Delete all remaining jobs of this encode.
3345                         // An encode can be composed of multiple associated jobs.
3346                         // When a job is stopped, libhb removes it from the job list,
3347                         // but does not remove other jobs that may be associated with it.
3348                         // Associated jobs are taged in the sequence id.
3349             while ((job = hb_job(h_queue, 0)) != NULL) 
3350                 hb_rem( h_queue, job );
3351                 } break;
3352 #undef p
3353     }
3354 }
3355
3356 gboolean
3357 ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
3358 {
3359         hb_list_t  * list;
3360         hb_title_t * title;
3361         
3362     if (h_scan == NULL) return FALSE;
3363         list = hb_get_titles( h_scan );
3364         if( !hb_list_count( list ) )
3365         {
3366                 /* No valid title, stop right there */
3367                 return FALSE;
3368         }
3369
3370         title = hb_list_item( list, titleindex );
3371         if (title == NULL) return FALSE;        // Bad titleindex
3372         tinfo->index = titleindex;
3373         tinfo->width = title->width;
3374         tinfo->height = title->height;
3375         memcpy(tinfo->crop, title->crop, 4 * sizeof(int));
3376         // Don't allow crop to 0
3377         if (title->crop[0] + title->crop[1] >= title->height)
3378                 title->crop[0] = title->crop[1] = 0;
3379         if (title->crop[2] + title->crop[3] >= title->width)
3380                 title->crop[2] = title->crop[3] = 0;
3381         tinfo->num_chapters = hb_list_count(title->list_chapter);
3382         tinfo->rate_base = title->rate_base;
3383         tinfo->rate = title->rate;
3384         tinfo->interlaced = title->detected_interlacing;
3385         hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), 
3386                                 title->width * title->pixel_aspect_width, 
3387                                 title->height * title->pixel_aspect_height);
3388         tinfo->hours = title->hours;
3389         tinfo->minutes = title->minutes;
3390         tinfo->seconds = title->seconds;
3391         tinfo->duration = title->duration;
3392
3393         tinfo->angle_count = title->angle_count;
3394         tinfo->path = title->path;
3395         tinfo->name = title->name;
3396         tinfo->type = title->type;
3397         return TRUE;
3398 }
3399
3400 hb_audio_config_t*
3401 ghb_get_scan_audio_info(gint titleindex, gint audioindex)
3402 {
3403     hb_audio_config_t *aconfig;
3404         
3405         aconfig = get_hb_audio(h_scan, titleindex, audioindex);
3406         return aconfig;
3407 }
3408
3409 gboolean
3410 ghb_audio_is_passthru(gint acodec)
3411 {
3412         g_debug("ghb_audio_is_passthru () \n");
3413         return (acodec & HB_ACODEC_PASS_FLAG) != 0;
3414 }
3415
3416 gboolean
3417 ghb_audio_can_passthru(gint acodec)
3418 {
3419         g_debug("ghb_audio_can_passthru () \n");
3420         return (acodec & HB_ACODEC_PASS_MASK) != 0;
3421 }
3422
3423 gint
3424 ghb_get_default_acodec()
3425 {
3426         return HB_ACODEC_FAAC;
3427 }
3428
3429 static void
3430 picture_settings_deps(signal_user_data_t *ud)
3431 {
3432         gboolean autoscale, keep_aspect, enable_keep_aspect;
3433         gboolean enable_scale_width, enable_scale_height;
3434         gboolean enable_disp_width, enable_disp_height, enable_par;
3435         gint pic_par;
3436         GtkWidget *widget;
3437
3438         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
3439         if (pic_par == 1)
3440         {
3441                 ghb_ui_update(ud, "autoscale", ghb_boolean_value(TRUE));
3442                 ghb_ui_update(ud, "PictureModulus", ghb_int_value(2));
3443                 ghb_ui_update(ud, "PictureLooseCrop", ghb_boolean_value(TRUE));
3444         }
3445         enable_keep_aspect = (pic_par != 1 && pic_par != 2);
3446         if (!enable_keep_aspect)
3447         {
3448                 ghb_ui_update(ud, "PictureKeepRatio", ghb_boolean_value(TRUE));
3449         }
3450         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
3451         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
3452
3453         enable_scale_width = !autoscale && (pic_par != 1);
3454         enable_scale_height = !autoscale && (pic_par != 1);
3455         enable_disp_width = (pic_par == 3) && !keep_aspect;
3456         enable_par = (pic_par == 3) && !keep_aspect;
3457         enable_disp_height = FALSE;
3458
3459         widget = GHB_WIDGET(ud->builder, "PictureModulus");
3460         gtk_widget_set_sensitive(widget, pic_par != 1);
3461         widget = GHB_WIDGET(ud->builder, "PictureLooseCrop");
3462         gtk_widget_set_sensitive(widget, pic_par != 1);
3463         widget = GHB_WIDGET(ud->builder, "scale_width");
3464         gtk_widget_set_sensitive(widget, enable_scale_width);
3465         widget = GHB_WIDGET(ud->builder, "scale_height");
3466         gtk_widget_set_sensitive(widget, enable_scale_height);
3467         widget = GHB_WIDGET(ud->builder, "PictureDisplayWidth");
3468         gtk_widget_set_sensitive(widget, enable_disp_width);
3469         widget = GHB_WIDGET(ud->builder, "PictureDisplayHeight");
3470         gtk_widget_set_sensitive(widget, enable_disp_height);
3471         widget = GHB_WIDGET(ud->builder, "PicturePARWidth");
3472         gtk_widget_set_sensitive(widget, enable_par);
3473         widget = GHB_WIDGET(ud->builder, "PicturePARHeight");
3474         gtk_widget_set_sensitive(widget, enable_par);
3475         widget = GHB_WIDGET(ud->builder, "PictureKeepRatio");
3476         gtk_widget_set_sensitive(widget, enable_keep_aspect);
3477         widget = GHB_WIDGET(ud->builder, "autoscale");
3478         gtk_widget_set_sensitive(widget, pic_par != 1);
3479 }
3480
3481 void
3482 ghb_set_scale(signal_user_data_t *ud, gint mode)
3483 {
3484         hb_list_t  * list;
3485         hb_title_t * title;
3486         hb_job_t   * job;
3487         gboolean keep_aspect;
3488         gint pic_par;
3489         gboolean autocrop, autoscale, noscale;
3490         gint crop[4], width, height, par_width, par_height;
3491         gint crop_width, crop_height;
3492         gint aspect_n, aspect_d;
3493         gboolean keep_width = (mode & GHB_PIC_KEEP_WIDTH);
3494         gboolean keep_height = (mode & GHB_PIC_KEEP_HEIGHT);
3495         gint step;
3496         GtkWidget *widget;
3497         gint mod;
3498         gint max_width = 0;
3499         gint max_height = 0;
3500         
3501         g_debug("ghb_set_scale ()\n");
3502         picture_settings_deps(ud);
3503         if (h_scan == NULL) return;
3504         list = hb_get_titles( h_scan );
3505         if( !hb_list_count( list ) )
3506         {
3507                 /* No valid title, stop right there */
3508                 return;
3509         }
3510         gint titleindex;
3511
3512         titleindex = ghb_settings_combo_int(ud->settings, "title");
3513         title = hb_list_item( list, titleindex );
3514         if (title == NULL) return;
3515         job   = title->job;
3516         if (job == NULL) return;
3517
3518         if (ud->scale_busy) return;
3519         ud->scale_busy = TRUE;
3520
3521         // First configure widgets
3522         mod = ghb_settings_combo_int(ud->settings, "PictureModulus");
3523         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
3524         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
3525         autocrop = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop");
3526         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
3527         // "Noscale" is a flag that says we prefer to crop extra to satisfy
3528         // alignment constraints rather than scaling to satisfy them.
3529         noscale = ghb_settings_get_boolean(ud->settings, "PictureLooseCrop");
3530         // Align dimensions to either 16 or 2 pixels
3531         // The scaler crashes if the dimensions are not divisible by 2
3532         // x264 also will not accept dims that are not multiple of 2
3533         if (autoscale)
3534         {
3535                 keep_width = FALSE;
3536                 keep_height = FALSE;
3537         }
3538         // Step needs to be at least 2 because odd widths cause scaler crash
3539         step = mod;
3540         widget = GHB_WIDGET (ud->builder, "scale_width");
3541         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3542         widget = GHB_WIDGET (ud->builder, "scale_height");
3543         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3544         if (noscale)
3545         {
3546                 widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
3547                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3548                 widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
3549                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3550                 widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
3551                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3552                 widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
3553                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
3554         }
3555         else
3556         {
3557                 widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
3558                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3559                 widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
3560                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3561                 widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
3562                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3563                 widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
3564                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
3565         }
3566         ghb_title_info_t tinfo;
3567         ghb_get_title_info (&tinfo, titleindex);
3568         if (autocrop)
3569         {
3570                 crop[0] = tinfo.crop[0];
3571                 crop[1] = tinfo.crop[1];
3572                 crop[2] = tinfo.crop[2];
3573                 crop[3] = tinfo.crop[3];
3574                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(crop[0]));
3575                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(crop[1]));
3576                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(crop[2]));
3577                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(crop[3]));
3578         }
3579         else
3580         {
3581                 crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
3582                 crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
3583                 crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
3584                 crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
3585         }
3586         if (noscale)
3587         {
3588                 gint need1, need2;
3589
3590                 // Adjust the cropping to accomplish the desired width and height
3591                 crop_width = tinfo.width - crop[2] - crop[3];
3592                 crop_height = tinfo.height - crop[0] - crop[1];
3593                 width = MOD_DOWN(crop_width, mod);
3594                 height = MOD_DOWN(crop_height, mod);
3595
3596                 need1 = (crop_height - height) / 2;
3597                 need2 = crop_height - height - need1;
3598                 crop[0] += need1;
3599                 crop[1] += need2;
3600                 need1 = (crop_width - width) / 2;
3601                 need2 = crop_width - width - need1;
3602                 crop[2] += need1;
3603                 crop[3] += need2;
3604                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(crop[0]));
3605                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(crop[1]));
3606                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(crop[2]));
3607                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(crop[3]));
3608         }
3609         hb_reduce(&aspect_n, &aspect_d, 
3610                                 title->width * title->pixel_aspect_width, 
3611                                 title->height * title->pixel_aspect_height);
3612         crop_width = title->width - crop[2] - crop[3];
3613         crop_height = title->height - crop[0] - crop[1];
3614         if (autoscale)
3615         {
3616                 width = crop_width;
3617                 height = crop_height;
3618         }
3619         else
3620         {
3621                 width = ghb_settings_get_int(ud->settings, "scale_width");
3622                 height = ghb_settings_get_int(ud->settings, "scale_height");
3623                 if (mode & GHB_PIC_USE_MAX)
3624                 {
3625                         max_width = MOD_DOWN(
3626                                 ghb_settings_get_int(ud->settings, "PictureWidth"), mod);
3627                         max_height = MOD_DOWN(
3628                                 ghb_settings_get_int(ud->settings, "PictureHeight"), mod);
3629                 }
3630         }
3631         g_debug("max_width %d, max_height %d\n", max_width, max_height);
3632
3633         if (width < 16)
3634                 width = title->width - crop[2] - crop[3];
3635         if (height < 16)
3636                 height = title->height - crop[0] - crop[1];
3637
3638         width = MOD_ROUND(width, mod);
3639         height = MOD_ROUND(height, mod);
3640
3641         job->anamorphic.mode = pic_par;
3642         if (pic_par)
3643         {
3644                 // The scaler crashes if the dimensions are not divisible by 2
3645                 // Align mod 2.  And so does something in x264_encoder_headers()
3646                 job->modulus = mod;
3647                 job->anamorphic.par_width = title->pixel_aspect_width;
3648                 job->anamorphic.par_height = title->pixel_aspect_height;
3649                 job->anamorphic.dar_width = 0;
3650                 job->anamorphic.dar_height = 0;
3651
3652                 if (keep_height && pic_par == 2)
3653                         width = ((double)height * crop_width / crop_height);
3654                 job->width = width;
3655                 job->height = height;
3656                 job->maxWidth = max_width;
3657                 job->maxHeight = max_height;
3658                 job->crop[0] = crop[0]; job->crop[1] = crop[1];
3659                 job->crop[2] = crop[2]; job->crop[3] = crop[3];
3660                 if (job->anamorphic.mode == 3 && !keep_aspect)
3661                 {
3662                         job->anamorphic.keep_display_aspect = 0;
3663                         if (mode & GHB_PIC_KEEP_PAR)
3664                         {
3665                                 job->anamorphic.par_width = 
3666                                         ghb_settings_get_int(ud->settings, "PicturePARWidth");
3667                                 job->anamorphic.par_height = 
3668                                         ghb_settings_get_int(ud->settings, "PicturePARHeight");
3669                         }
3670                         else
3671                         {
3672                                 job->anamorphic.dar_width = 
3673                                         ghb_settings_get_int(ud->settings, 
3674                                                                                 "PictureDisplayWidth");
3675                                 job->anamorphic.dar_height = height;
3676                         }
3677                 }
3678                 else
3679                 {
3680                         job->anamorphic.keep_display_aspect = 1;
3681                 }
3682                 // hb_set_anamorphic_size will adjust par, dar, and width/height
3683                 // to conform to job parameters that have been set, including 
3684                 // maxWidth and maxHeight
3685                 hb_set_anamorphic_size( job, &width, &height, 
3686                                                                 &par_width, &par_height );
3687                 if (job->anamorphic.mode == 3 && !keep_aspect && 
3688                         mode & GHB_PIC_KEEP_PAR)
3689                 {
3690                         // hb_set_anamorphic_size reduces the par, which we
3691                         // don't want in this case because the user is
3692                         // explicitely specifying it.
3693                         par_width = ghb_settings_get_int(ud->settings, 
3694                                                                                         "PicturePARWidth");
3695                         par_height = ghb_settings_get_int(ud->settings, 
3696                                                                                                 "PicturePARHeight");
3697                 }
3698         }
3699         else 
3700         {
3701                 // Adjust dims according to max values
3702                 if (max_height)
3703                         height = MIN(height, max_height);
3704                 if (max_width)
3705                         width = MIN(width, max_width);
3706
3707                 if (keep_aspect)
3708                 {
3709                         gdouble par;
3710                         gint new_width, new_height;
3711                         
3712                         // Compute pixel aspect ration.  
3713                         par = (gdouble)(title->height * aspect_n) / (title->width * aspect_d);
3714                         // Must scale so that par becomes 1:1
3715                         // Try to keep largest dimension
3716                         new_height = (crop_height * ((gdouble)width/crop_width) / par);
3717                         new_width = (crop_width * ((gdouble)height/crop_height) * par);
3718
3719                         if (max_width && new_width > max_width)
3720                         {
3721                                 height = new_height;
3722                         }
3723                         else if (max_height && new_height > max_height)
3724                         {
3725                                 width = new_width;
3726                         }
3727                         else if (keep_width)
3728                         {
3729                                 height = new_height;
3730                         }
3731                         else if (keep_height)
3732                         {
3733                                 width = new_width;
3734                         }
3735                         else if (width > new_width)
3736                         {
3737                                 height = new_height;
3738                         }
3739                         else
3740                         {
3741                                 width = new_width;
3742                         }
3743                         g_debug("new w %d h %d\n", width, height);
3744                 }
3745                 width = MOD_ROUND(width, mod);
3746                 height = MOD_ROUND(height, mod);
3747                 if (max_height)
3748                         height = MIN(height, max_height);
3749                 if (max_width)
3750                         width = MIN(width, max_width);
3751                 par_width = par_height = 1;
3752         }
3753         ghb_ui_update(ud, "scale_width", ghb_int64_value(width));
3754         ghb_ui_update(ud, "scale_height", ghb_int64_value(height));
3755
3756         gint disp_width, dar_width, dar_height;
3757         gchar *str;
3758
3759         disp_width = (gdouble)(width * par_width / par_height) + 0.5;
3760         hb_reduce(&dar_width, &dar_height, disp_width, height);
3761                 
3762         gint iaspect = dar_width * 9 / dar_height;
3763         if (dar_width > 2 * dar_height)
3764         {
3765                 str = g_strdup_printf("%.2f : 1", (gdouble)dar_width / dar_height);
3766         }
3767         else if (iaspect <= 16 && iaspect >= 15)
3768         {
3769                 str = g_strdup_printf("%.2f : 9", (gdouble)dar_width * 9 / dar_height);
3770         }
3771         else if (iaspect <= 12 && iaspect >= 11)
3772         {
3773                 str = g_strdup_printf("%.2f : 3", (gdouble)dar_width * 3 / dar_height);
3774         }
3775         else
3776         {
3777                 str = g_strdup_printf("%d : %d", dar_width, dar_height);
3778         }
3779         ghb_ui_update(ud, "display_aspect", ghb_string_value(str));
3780         g_free(str);
3781         ghb_ui_update(ud, "PicturePARWidth", ghb_int64_value(par_width));
3782         ghb_ui_update(ud, "PicturePARHeight", ghb_int64_value(par_height));
3783         ghb_ui_update(ud, "PictureDisplayWidth", ghb_int64_value(disp_width));
3784         ghb_ui_update(ud, "PictureDisplayHeight", ghb_int64_value(height));
3785         ud->scale_busy = FALSE;
3786 }
3787
3788 static void
3789 set_preview_job_settings(hb_job_t *job, GValue *settings)
3790 {
3791         job->crop[0] = ghb_settings_get_int(settings, "PictureTopCrop");
3792         job->crop[1] = ghb_settings_get_int(settings, "PictureBottomCrop");
3793         job->crop[2] = ghb_settings_get_int(settings, "PictureLeftCrop");
3794         job->crop[3] = ghb_settings_get_int(settings, "PictureRightCrop");
3795
3796         job->anamorphic.mode = ghb_settings_combo_int(settings, "PicturePAR");
3797         job->modulus = 
3798                 ghb_settings_combo_int(settings, "PictureModulus");
3799         job->width = ghb_settings_get_int(settings, "scale_width");
3800         job->height = ghb_settings_get_int(settings, "scale_height");
3801         if (ghb_settings_get_boolean(settings, "show_crop"))
3802         {
3803                 gdouble xscale = (gdouble)job->width / 
3804                         (gdouble)(job->title->width - job->crop[2] - job->crop[3]);
3805                 gdouble yscale = (gdouble)job->height / 
3806                         (gdouble)(job->title->height - job->crop[0] - job->crop[1]);
3807         
3808                 job->width += xscale * (job->crop[2] + job->crop[3]);
3809                 job->height += yscale * (job->crop[0] + job->crop[1]);
3810                 job->crop[0] = 0;
3811                 job->crop[1] = 0;
3812                 job->crop[2] = 0;
3813                 job->crop[3] = 0;
3814                 job->modulus = 2;
3815         }
3816
3817         gboolean decomb_deint = ghb_settings_get_boolean(settings, "PictureDecombDeinterlace");
3818         if (decomb_deint)
3819         {
3820                 gint decomb = ghb_settings_combo_int(settings, "PictureDecomb");
3821                 job->deinterlace = (decomb == 0) ? 0 : 1;
3822         }
3823         else
3824         {
3825                 gint deint = ghb_settings_combo_int(settings, "PictureDeinterlace");
3826                 job->deinterlace = (deint == 0) ? 0 : 1;
3827         }
3828
3829         gboolean keep_aspect;
3830         keep_aspect = ghb_settings_get_boolean(settings, "PictureKeepRatio");
3831         if (job->anamorphic.mode)
3832         {
3833                 job->anamorphic.par_width = job->title->pixel_aspect_width;
3834                 job->anamorphic.par_height = job->title->pixel_aspect_height;
3835                 job->anamorphic.dar_width = 0;
3836                 job->anamorphic.dar_height = 0;
3837
3838                 if (job->anamorphic.mode == 3 && !keep_aspect)
3839                 {
3840                         job->anamorphic.keep_display_aspect = 0;
3841                         job->anamorphic.par_width = 
3842                                 ghb_settings_get_int(settings, "PicturePARWidth");
3843                         job->anamorphic.par_height = 
3844                                 ghb_settings_get_int(settings, "PicturePARHeight");
3845                 }
3846                 else
3847                 {
3848                         job->anamorphic.keep_display_aspect = 1;
3849                 }
3850         }
3851 }
3852
3853 gint
3854 ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
3855 {
3856         hb_list_t  * list;
3857         hb_title_t * title;
3858         hb_job_t   * job;
3859         gint size;
3860
3861         if (h_scan == NULL) return 1500;
3862         list = hb_get_titles( h_scan );
3863     title = hb_list_item( list, titleindex );
3864         if (title == NULL) return 1500;
3865         job   = title->job;
3866         if (job == NULL) return 1500;
3867         size = ghb_settings_get_int(settings, "VideoTargetSize");
3868         return hb_calc_bitrate( job, size );
3869 }
3870
3871 gboolean
3872 ghb_validate_filter_string(const gchar *str, gint max_fields)
3873 {
3874         gint fields = 0;
3875         gchar *end;
3876         gdouble val;
3877
3878         if (str == NULL || *str == 0) return TRUE;
3879         while (*str)
3880         {
3881                 val = g_strtod(str, &end);
3882                 if (str != end)
3883                 { // Found a numeric value
3884                         fields++;
3885                         // negative max_fields means infinate
3886                         if (max_fields >= 0 && fields > max_fields) return FALSE;
3887                         if (*end == 0)
3888                                 return TRUE;
3889                         if (*end != ':')
3890                                 return FALSE;
3891                         str = end + 1;
3892                 }
3893                 else
3894                         return FALSE;
3895         }
3896         return FALSE;
3897 }
3898
3899 gboolean
3900 ghb_validate_filters(signal_user_data_t *ud)
3901 {
3902         gchar *str;
3903         gint index;
3904         gchar *message;
3905
3906         gboolean decomb_deint = ghb_settings_get_boolean(ud->settings, "PictureDecombDeinterlace");
3907         // deinte
3908         index = ghb_settings_combo_int(ud->settings, "PictureDeinterlace");
3909         if (!decomb_deint && index == 1)
3910         {
3911                 str = ghb_settings_get_string(ud->settings, "PictureDeinterlaceCustom");
3912                 if (!ghb_validate_filter_string(str, -1))
3913                 {
3914                         message = g_strdup_printf(
3915                                                 "Invalid Deinterlace Settings:\n\n%s\n",
3916                                                 str);
3917                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3918                         g_free(message);
3919                         g_free(str);
3920                         return FALSE;
3921                 }
3922                 g_free(str);
3923         }
3924         // detel
3925         index = ghb_settings_combo_int(ud->settings, "PictureDetelecine");
3926         if (index == 1)
3927         {
3928                 str = ghb_settings_get_string(ud->settings, "PictureDetelecineCustom");
3929                 if (!ghb_validate_filter_string(str, -1))
3930                 {
3931                         message = g_strdup_printf(
3932                                                 "Invalid Detelecine Settings:\n\n%s\n",
3933                                                 str);
3934                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3935                         g_free(message);
3936                         g_free(str);
3937                         return FALSE;
3938                 }
3939                 g_free(str);
3940         }
3941         // decomb
3942         index = ghb_settings_combo_int(ud->settings, "PictureDecomb");
3943         if (decomb_deint && index == 1)
3944         {
3945                 str = ghb_settings_get_string(ud->settings, "PictureDecombCustom");
3946                 if (!ghb_validate_filter_string(str, -1))
3947                 {
3948                         message = g_strdup_printf(
3949                                                 "Invalid Decomb Settings:\n\n%s\n",
3950                                                 str);
3951                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3952                         g_free(message);
3953                         g_free(str);
3954                         return FALSE;
3955                 }
3956                 g_free(str);
3957         }
3958         // denois
3959         index = ghb_settings_combo_int(ud->settings, "PictureDenoise");
3960         if (index == 1)
3961         {
3962                 str = ghb_settings_get_string(ud->settings, "PictureDenoiseCustom");
3963                 if (!ghb_validate_filter_string(str, -1))
3964                 {
3965                         message = g_strdup_printf(
3966                                                 "Invalid Denoise Settings:\n\n%s\n",
3967                                                 str);
3968                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3969                         g_free(str);
3970                         g_free(message);
3971                         return FALSE;
3972                 }
3973                 g_free(str);
3974         }
3975         return TRUE;
3976 }
3977
3978 gboolean
3979 ghb_validate_video(signal_user_data_t *ud)
3980 {
3981         gint vcodec, mux;
3982         gchar *message;
3983
3984         mux = ghb_settings_combo_int(ud->settings, "FileFormat");
3985         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
3986         if ((mux == HB_MUX_MP4) && (vcodec == HB_VCODEC_THEORA))
3987         {
3988                 // mp4/theora combination is not supported.
3989                 message = g_strdup_printf(
3990                                         "Theora is not supported in the MP4 container.\n\n"
3991                                         "You should choose a different video codec or container.\n"
3992                                         "If you continue, FFMPEG will be chosen for you.");
3993                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3994                 {
3995                         g_free(message);
3996                         return FALSE;
3997                 }
3998                 g_free(message);
3999                 vcodec = HB_VCODEC_FFMPEG;
4000                 ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
4001         }
4002         return TRUE;
4003 }
4004
4005 gboolean
4006 ghb_validate_subtitles(signal_user_data_t *ud)
4007 {
4008         hb_list_t  * list;
4009         hb_title_t * title;
4010         gchar *message;
4011
4012         if (h_scan == NULL) return FALSE;
4013         list = hb_get_titles( h_scan );
4014         if( !hb_list_count( list ) )
4015         {
4016                 /* No valid title, stop right there */
4017                 g_message("No title found.\n");
4018                 return FALSE;
4019         }
4020
4021         gint titleindex;
4022
4023         titleindex = ghb_settings_combo_int(ud->settings, "title");
4024     title = hb_list_item( list, titleindex );
4025         if (title == NULL) return FALSE;
4026
4027         const GValue *slist, *settings;
4028         gint count, ii, source;
4029         gboolean burned, one_burned = FALSE;
4030
4031         slist = ghb_settings_get_value(ud->settings, "subtitle_list");
4032         count = ghb_array_len(slist);
4033         for (ii = 0; ii < count; ii++)
4034         {
4035                 settings = ghb_array_get_nth(slist, ii);
4036                 source = ghb_settings_get_int(settings, "SubtitleSource");
4037                 burned = ghb_settings_get_boolean(settings, "SubtitleBurned");
4038                 if (burned && one_burned)
4039                 {
4040                         // MP4 can only handle burned vobsubs.  make sure there isn't
4041                         // already something burned in the list
4042                         message = g_strdup_printf(
4043                         "Only one subtitle may be burned into the video.\n\n"
4044                                 "You should change your subtitle selections.\n"
4045                                 "If you continue, some subtitles will be lost.");
4046                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4047                         {
4048                                 g_free(message);
4049                                 return FALSE;
4050                         }
4051                         g_free(message);
4052                         break;
4053                 }
4054                 else if (burned)
4055                 {
4056                         one_burned = TRUE;
4057                 }
4058                 if (source == SRTSUB)
4059                 {
4060                         gchar *filename;
4061
4062                         filename = ghb_settings_get_string(settings, "SrtFile");
4063                         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
4064                         {
4065                                 message = g_strdup_printf(
4066                                 "Srt file does not exist or not a regular file.\n\n"
4067                                         "You should choose a valid file.\n"
4068                                         "If you continue, this subtitle will be ignored.");
4069                                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, 
4070                                         "Cancel", "Continue"))
4071                                 {
4072                                         g_free(message);
4073                                         return FALSE;
4074                                 }
4075                                 g_free(message);
4076                                 break;
4077                         }
4078                 }
4079         }
4080         return TRUE;
4081 }
4082
4083 gint
4084 ghb_select_audio_codec(GValue *settings, hb_audio_config_t *aconfig, gint acodec)
4085 {
4086         gint mux = ghb_settings_combo_int(settings, "FileFormat");
4087
4088         guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK;
4089         if (mux == HB_MUX_MP4)
4090         {
4091                 if ((acodec & in_codec & HB_ACODEC_AC3))
4092                 {
4093                         return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4094                 }
4095                 else if (acodec & HB_ACODEC_AC3)
4096                 {
4097                         return HB_ACODEC_AC3;
4098                 }
4099                 else if (acodec & HB_ACODEC_LAME)
4100                 {
4101                         return HB_ACODEC_LAME;
4102                 }
4103                 else if (acodec & HB_ACODEC_FAAC)
4104                 {
4105                         return HB_ACODEC_FAAC;
4106                 }
4107                 else
4108                 {
4109                         return HB_ACODEC_FAAC;
4110                 }
4111         }
4112         else
4113         {
4114                 if ((acodec & in_codec & HB_ACODEC_PASS_MASK))
4115                 {
4116                         return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4117                 }
4118                 else if (acodec & HB_ACODEC_AC3)
4119                 {
4120                         return HB_ACODEC_AC3;
4121                 }
4122                 else if (acodec & HB_ACODEC_VORBIS)
4123                 {
4124                         return HB_ACODEC_VORBIS;
4125                 }
4126                 else if (acodec & HB_ACODEC_LAME)
4127                 {
4128                         return HB_ACODEC_LAME;
4129                 }
4130                 else if (acodec & HB_ACODEC_FAAC)
4131                 {
4132                         return HB_ACODEC_FAAC;
4133                 }
4134                 else
4135                 {
4136                         return HB_ACODEC_LAME;
4137                 }
4138         }
4139 }
4140
4141 gboolean
4142 ghb_validate_audio(signal_user_data_t *ud)
4143 {
4144         hb_list_t  * list;
4145         hb_title_t * title;
4146         gchar *message;
4147         GValue *value;
4148
4149         if (h_scan == NULL) return FALSE;
4150         list = hb_get_titles( h_scan );
4151         if( !hb_list_count( list ) )
4152         {
4153                 /* No valid title, stop right there */
4154                 g_message("No title found.\n");
4155                 return FALSE;
4156         }
4157
4158         gint titleindex;
4159
4160         titleindex = ghb_settings_combo_int(ud->settings, "title");
4161     title = hb_list_item( list, titleindex );
4162         if (title == NULL) return FALSE;
4163         gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
4164
4165         const GValue *audio_list;
4166         gint count, ii;
4167
4168         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
4169         count = ghb_array_len(audio_list);
4170         for (ii = 0; ii < count; ii++)
4171         {
4172                 GValue *asettings;
4173             hb_audio_config_t *aconfig;
4174
4175                 asettings = ghb_array_get_nth(audio_list, ii);
4176                 gint track = ghb_settings_combo_int(asettings, "AudioTrack");
4177                 gint codec = ghb_settings_combo_int(asettings, "AudioEncoder");
4178                 if (codec == HB_ACODEC_ANY)
4179                         continue;
4180
4181         aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
4182                                                                                         title->list_audio, track );
4183                 if ( ghb_audio_is_passthru(codec) &&
4184                         !(ghb_audio_can_passthru(aconfig->in.codec) && 
4185                          (aconfig->in.codec & codec)))
4186                 {
4187                         // Not supported.  AC3 is passthrough only, so input must be AC3
4188                         message = g_strdup_printf(
4189                                                 "The source does not support Pass-Thru.\n\n"
4190                                                 "You should choose a different audio codec.\n"
4191                                                 "If you continue, one will be chosen for you.");
4192                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4193                         {
4194                                 g_free(message);
4195                                 return FALSE;
4196                         }
4197                         g_free(message);
4198                         if ((codec & HB_ACODEC_AC3) ||
4199                                 aconfig->in.codec == HB_ACODEC_DCA)
4200                         {
4201                                 codec = HB_ACODEC_AC3;
4202                         }
4203                         else if (mux == HB_MUX_MKV)
4204                         {
4205                                 codec = HB_ACODEC_LAME;
4206                         }
4207                         else
4208                         {
4209                                 codec = HB_ACODEC_FAAC;
4210                         }
4211                         value = ghb_lookup_acodec_value(codec);
4212                         ghb_settings_take_value(asettings, "AudioEncoder", value);
4213                 }
4214                 gchar *a_unsup = NULL;
4215                 gchar *mux_s = NULL;
4216                 if (mux == HB_MUX_MP4)
4217                 { 
4218                         mux_s = "MP4";
4219                         // mp4/vorbis|DTS combination is not supported.
4220                         if (codec == HB_ACODEC_VORBIS)
4221                         {
4222                                 a_unsup = "Vorbis";
4223                                 codec = HB_ACODEC_FAAC;
4224                         }
4225                         if (codec == HB_ACODEC_DCA)
4226                         {
4227                                 a_unsup = "DTS";
4228                                 codec = HB_ACODEC_AC3;
4229                         }
4230                 }
4231                 if (a_unsup)
4232                 {
4233                         message = g_strdup_printf(
4234                                                 "%s is not supported in the %s container.\n\n"
4235                                                 "You should choose a different audio codec.\n"
4236                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
4237                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4238                         {
4239                                 g_free(message);
4240                                 return FALSE;
4241                         }
4242                         g_free(message);
4243                         value = ghb_lookup_acodec_value(codec);
4244                         ghb_settings_take_value(asettings, "AudioEncoder", value);
4245                 }
4246
4247                 gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
4248                 gboolean allow_mono = TRUE;
4249                 gboolean allow_stereo = TRUE;
4250                 gboolean allow_dolby = TRUE;
4251                 gboolean allow_dpl2 = TRUE;
4252                 gboolean allow_6ch = TRUE;
4253                 allow_mono = TRUE;
4254
4255                 gint best = hb_get_best_mixdown(codec, aconfig->in.channel_layout, 0);
4256
4257                 allow_stereo = best >= HB_AMIXDOWN_STEREO;
4258                 allow_dolby = best >= HB_AMIXDOWN_DOLBY;
4259                 allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
4260                 allow_6ch = best >= HB_AMIXDOWN_6CH;
4261
4262                 gchar *mix_unsup = NULL;
4263                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
4264                 {
4265                         mix_unsup = "mono";
4266                 }
4267                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
4268                 {
4269                         mix_unsup = "stereo";
4270                 }
4271                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
4272                 {
4273                         mix_unsup = "Dolby";
4274                 }
4275                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
4276                 {
4277                         mix_unsup = "Dolby Pro Logic II";
4278                 }
4279                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
4280                 {
4281                         mix_unsup = "6 Channel";
4282                 }
4283                 if (mix_unsup)
4284                 {
4285                         message = g_strdup_printf(
4286                                                 "The source audio does not support %s mixdown.\n\n"
4287                                                 "You should choose a different mixdown.\n"
4288                                                 "If you continue, one will be chosen for you.", mix_unsup);
4289                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
4290                         {
4291                                 g_free(message);
4292                                 return FALSE;
4293                         }
4294                         g_free(message);
4295                         mix = ghb_get_best_mix(aconfig, codec, mix);
4296                         value = get_amix_value(mix);
4297                         ghb_settings_take_value(asettings, "AudioMixdown", value);
4298                 }
4299         }
4300         return TRUE;
4301 }
4302
4303 gboolean
4304 ghb_validate_vquality(GValue *settings)
4305 {
4306         gint vcodec;
4307         gchar *message;
4308         gint min, max;
4309
4310         if (ghb_settings_get_boolean(settings, "nocheckvquality")) return TRUE;
4311         vcodec = ghb_settings_combo_int(settings, "VideoEncoder");
4312         gdouble vquality;
4313         vquality = ghb_settings_get_double(settings, "VideoQualitySlider");
4314         if (ghb_settings_get_boolean(settings, "vquality_type_constant"))
4315         {
4316                 switch (vcodec)
4317                 {
4318                         case HB_VCODEC_X264:
4319                         {
4320                                 min = 16;
4321                                 max = 30;
4322                         } break;
4323
4324                         case HB_VCODEC_FFMPEG:
4325                         {
4326                                 min = 1;
4327                                 max = 8;
4328                         } break;
4329
4330                         case HB_VCODEC_THEORA:
4331                         {
4332                                 min = 0;
4333                                 max = 63;
4334                         } break;
4335
4336                         default:
4337                         {
4338                                 min = 48;
4339                                 max = 62;
4340                         } break;
4341                 }
4342                 if (vcodec == HB_VCODEC_X264 && vquality == 0.0)
4343                 {
4344                         message = g_strdup_printf(
4345                                                 "Warning: lossless h.264 selected\n\n"
4346                                                 "Lossless h.264 is not well supported by\n"
4347                                                 "many players and editors.\n\n"
4348                         "It will produce enormous output files.\n\n"
4349                                                 "Are you sure you wish to use this setting?",
4350                                                 (gint)vquality, min, max);
4351                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
4352                                                                         "Cancel", "Continue"))
4353                         {
4354                                 g_free(message);
4355                                 return FALSE;
4356                         }
4357                         g_free(message);
4358                 }
4359                 else if (vquality < min || vquality > max)
4360                 {
4361                         message = g_strdup_printf(
4362                                                 "Interesting video quality choice: %d\n\n"
4363                                                 "Typical values range from %d to %d.\n\n"
4364                                                 "Are you sure you wish to use this setting?",
4365                                                 (gint)vquality, min, max);
4366                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
4367                                                                         "Cancel", "Continue"))
4368                         {
4369                                 g_free(message);
4370                                 return FALSE;
4371                         }
4372                         g_free(message);
4373                 }
4374         }
4375         return TRUE;
4376 }
4377
4378 static void
4379 add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
4380 {
4381         hb_list_t  * list;
4382         hb_title_t * title;
4383         hb_job_t   * job;
4384         static gchar *x264opts;
4385         gint sub_id = 0;
4386         gboolean tweaks = FALSE;
4387         gchar *detel_str = NULL;
4388         gchar *decomb_str = NULL;
4389         gchar *deint_str = NULL;
4390         gchar *deblock_str = NULL;
4391         gchar *denoise_str = NULL;
4392         gchar *dest_str = NULL;
4393
4394         g_debug("add_job()\n");
4395         if (h == NULL) return;
4396         list = hb_get_titles( h );
4397         if( !hb_list_count( list ) )
4398         {
4399                 /* No valid title, stop right there */
4400                 return;
4401         }
4402
4403     title = hb_list_item( list, titleindex );
4404         if (title == NULL) return;
4405
4406         /* Set job settings */
4407         job   = title->job;
4408         if (job == NULL) return;
4409
4410         job->angle = ghb_settings_get_int(js, "angle");
4411         job->start_at_preview = ghb_settings_get_int(js, "start_frame") + 1;
4412         if (job->start_at_preview)
4413         {
4414                 job->seek_points = ghb_settings_get_int(js, "preview_count");
4415                 job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL;
4416         }
4417
4418         tweaks = ghb_settings_get_boolean(js, "allow_tweaks");
4419         job->mux = ghb_settings_combo_int(js, "FileFormat");
4420         if (job->mux == HB_MUX_MP4)
4421         {
4422                 job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile");
4423                 job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize");
4424         }
4425         else
4426         {
4427                 job->largeFileSize = FALSE;
4428                 job->mp4_optimize = FALSE;
4429         }
4430         if (!job->start_at_preview)
4431         {
4432                 gint start, end;
4433                 gint num_chapters = hb_list_count(title->list_chapter);
4434                 gint duration = title->duration / 90000;
4435                 job->chapter_start = 1;
4436                 job->chapter_end = num_chapters;
4437
4438                 if (ghb_settings_combo_int(js, "PtoPType") == 0)
4439                 {
4440                         start = ghb_settings_get_int(js, "start_point");
4441                         end = ghb_settings_get_int(js, "end_point");
4442                         job->chapter_start = MIN( num_chapters, start );
4443                         job->chapter_end   = MAX( job->chapter_start, end );
4444
4445                 }
4446                 if (ghb_settings_combo_int(js, "PtoPType") == 1)
4447                 {
4448                         job->chapter_start = 1;
4449                         job->chapter_end = num_chapters;
4450                         start = ghb_settings_get_int(js, "start_point");
4451                         end = ghb_settings_get_int(js, "end_point");
4452                         job->pts_to_start = (int64_t)MIN(duration-1, start) * 90000;
4453                         job->pts_to_stop = (int64_t)MAX(start+1, end) * 90000 - 
4454                                                                 job->pts_to_start;
4455                 }
4456                 if (ghb_settings_combo_int(js, "PtoPType") == 2)
4457                 {
4458                         job->chapter_start = 1;
4459                         job->chapter_end = num_chapters;
4460                         start = ghb_settings_get_int(js, "start_point");
4461                         end = ghb_settings_get_int(js, "end_point");
4462                         gint64 max_frames;
4463                         max_frames = (gint64)duration * title->rate / title->rate_base;
4464                         job->frame_to_start = (int64_t)MIN(max_frames-1, start-1);
4465                         job->frame_to_stop = (int64_t)MAX(start, end-1) - 
4466                                                                  job->frame_to_start;
4467                 }
4468                 job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
4469                 if (job->chapter_start == job->chapter_end)
4470                         job->chapter_markers = 0;
4471                 if ( job->chapter_markers )
4472                 {
4473                         GValue *chapters;
4474                         GValue *chapter;
4475                         gint chap;
4476                         gint count;
4477
4478                         chapters = ghb_settings_get_value(js, "chapter_list");
4479                         count = ghb_array_len(chapters);
4480                         for(chap = 0; chap < count; chap++)
4481                         {
4482                                 hb_chapter_t * chapter_s;
4483                                 gchar *name;
4484
4485                                 name = NULL;
4486                                 chapter = ghb_array_get_nth(chapters, chap);
4487                                 name = ghb_value_string(chapter); 
4488                                 if (name == NULL)
4489                                 {
4490                                         name = g_strdup_printf ("Chapter %2d", chap+1);
4491                                 }
4492                                 chapter_s = hb_list_item( job->title->list_chapter, chap);
4493                                 strncpy(chapter_s->title, name, 1023);
4494                                 chapter_s->title[1023] = '\0';
4495                                 g_free(name);
4496                         }
4497                 }
4498         }
4499         job->crop[0] = ghb_settings_get_int(js, "PictureTopCrop");
4500         job->crop[1] = ghb_settings_get_int(js, "PictureBottomCrop");
4501         job->crop[2] = ghb_settings_get_int(js, "PictureLeftCrop");
4502         job->crop[3] = ghb_settings_get_int(js, "PictureRightCrop");
4503
4504         
4505         gboolean decomb_deint = ghb_settings_get_boolean(js, "PictureDecombDeinterlace");
4506         gint decomb = ghb_settings_combo_int(js, "PictureDecomb");
4507         gint deint = ghb_settings_combo_int(js, "PictureDeinterlace");
4508         if (!decomb_deint)
4509                 job->deinterlace = (deint != 0) ? 1 : 0;
4510         else
4511                 job->deinterlace = 0;
4512     job->grayscale   = ghb_settings_get_boolean(js, "VideoGrayScale");
4513
4514         gboolean keep_aspect;
4515         keep_aspect = ghb_settings_get_boolean(js, "PictureKeepRatio");
4516         job->anamorphic.mode = ghb_settings_combo_int(js, "PicturePAR");
4517         job->modulus = ghb_settings_combo_int(js, "PictureModulus");
4518         if (job->anamorphic.mode)
4519         {
4520                 job->anamorphic.par_width = title->pixel_aspect_width;
4521                 job->anamorphic.par_height = title->pixel_aspect_height;
4522                 job->anamorphic.dar_width = 0;
4523                 job->anamorphic.dar_height = 0;
4524
4525                 if (job->anamorphic.mode == 3 && !keep_aspect)
4526                 {
4527                         job->anamorphic.keep_display_aspect = 0;
4528                         job->anamorphic.par_width = 
4529                                 ghb_settings_get_int(js, "PicturePARWidth");
4530                         job->anamorphic.par_height = 
4531                                 ghb_settings_get_int(js, "PicturePARHeight");
4532                 }
4533                 else
4534                 {
4535                         job->anamorphic.keep_display_aspect = 1;
4536                 }
4537         }
4538
4539         /* Add selected filters */
4540         job->filters = hb_list_init();
4541         gint detel = ghb_settings_combo_int(js, "PictureDetelecine");
4542         if ( detel )
4543         {
4544                 if (detel != 1)
4545                 {
4546                         if (detel_opts.map[detel].svalue != NULL)
4547                                 detel_str = g_strdup(detel_opts.map[detel].svalue);
4548                 }
4549                 else
4550                         detel_str = ghb_settings_get_string(js, "PictureDetelecineCustom");
4551                 hb_filter_detelecine.settings = detel_str;
4552                 hb_list_add( job->filters, &hb_filter_detelecine );
4553         }
4554         if ( decomb_deint && decomb )
4555         {
4556                 if (decomb != 1)
4557                 {
4558                         if (decomb_opts.map[decomb].svalue != NULL)
4559                                 decomb_str = g_strdup(decomb_opts.map[decomb].svalue);
4560                 }
4561                 else
4562                         decomb_str = ghb_settings_get_string(js, "PictureDecombCustom");
4563                 hb_filter_decomb.settings = decomb_str;
4564                 hb_list_add( job->filters, &hb_filter_decomb );
4565         }
4566         if( job->deinterlace )
4567         {
4568                 if (deint != 1)
4569                 {
4570                         if (deint_opts.map[deint].svalue != NULL)
4571                                 deint_str = g_strdup(deint_opts.map[deint].svalue);
4572                 }
4573                 else
4574                         deint_str = ghb_settings_get_string(js, "PictureDeinterlaceCustom");
4575                 hb_filter_deinterlace.settings = deint_str;
4576                 hb_list_add( job->filters, &hb_filter_deinterlace );
4577         }
4578         gint deblock = ghb_settings_get_int(js, "PictureDeblock");
4579         if( deblock >= 5 )
4580         {
4581                 deblock_str = g_strdup_printf("%d", deblock);
4582                 hb_filter_deblock.settings = deblock_str;
4583                 hb_list_add( job->filters, &hb_filter_deblock );
4584         }
4585         gint denoise = ghb_settings_combo_int(js, "PictureDenoise");
4586         if( denoise )
4587         {
4588                 if (denoise != 1)
4589                 {
4590                         if (denoise_opts.map[denoise].svalue != NULL)
4591                                 denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
4592                 }
4593                 else
4594                         denoise_str = ghb_settings_get_string(js, "PictureDenoiseCustom");
4595                 hb_filter_denoise.settings = denoise_str;
4596                 hb_list_add( job->filters, &hb_filter_denoise );
4597         }
4598         job->width = ghb_settings_get_int(js, "scale_width");
4599         job->height = ghb_settings_get_int(js, "scale_height");
4600
4601         job->vcodec = ghb_settings_combo_int(js, "VideoEncoder");
4602         if ((job->mux == HB_MUX_MP4 ) && (job->vcodec == HB_VCODEC_THEORA))
4603         {
4604                 // mp4/theora combination is not supported.
4605                 job->vcodec = HB_VCODEC_FFMPEG;
4606         }
4607         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
4608         {
4609                 job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible");
4610         }
4611         if (ghb_settings_get_boolean(js, "vquality_type_constant"))
4612         {
4613                 gdouble vquality;
4614                 vquality = ghb_settings_get_double(js, "VideoQualitySlider");
4615                 job->vquality =  vquality;
4616                 job->vbitrate = 0;
4617         }
4618         else if (ghb_settings_get_boolean(js, "vquality_type_bitrate"))
4619         {
4620                 job->vquality = -1.0;
4621                 job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
4622         }
4623
4624         gint vrate = ghb_settings_combo_int(js, "VideoFramerate");
4625         if( vrate == 0 )
4626         {
4627                 job->vrate = title->rate;
4628                 job->vrate_base = title->rate_base;
4629                 job->cfr = 0;
4630         }
4631         else
4632         {
4633                 job->vrate = 27000000;
4634                 job->vrate_base = vrate;
4635                 gboolean pfr = ghb_settings_get_boolean(js, "VideoFrameratePFR");
4636                 if (pfr)
4637                         job->cfr = 2;
4638                 else
4639                         job->cfr = 1;
4640         }
4641
4642         const GValue *audio_list;
4643         gint count, ii;
4644         gint tcount = 0;
4645         
4646         audio_list = ghb_settings_get_value(js, "audio_list");
4647         count = ghb_array_len(audio_list);
4648         for (ii = 0; ii < count; ii++)
4649         {
4650                 GValue *asettings;
4651             hb_audio_config_t audio;
4652             hb_audio_config_t *aconfig;
4653                 gint acodec;
4654
4655                 hb_audio_config_init(&audio);
4656                 asettings = ghb_array_get_nth(audio_list, ii);
4657                 audio.in.track = ghb_settings_get_int(asettings, "AudioTrack");
4658                 audio.out.track = tcount;
4659
4660         aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
4661                                                                         title->list_audio, audio.in.track );
4662
4663                 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
4664                 audio.out.codec = ghb_select_audio_codec(js, aconfig, acodec);
4665
4666         audio.out.dynamic_range_compression = 
4667                         ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
4668         if (audio.out.dynamic_range_compression < 1.0)
4669                 audio.out.dynamic_range_compression = 0.0;
4670
4671                 // It would be better if this were done in libhb for us, but its not yet.
4672                 if (ghb_audio_is_passthru(audio.out.codec))
4673                 {
4674                         audio.out.mixdown = 0;
4675                 }
4676                 else
4677                 {
4678                         audio.out.mixdown = ghb_settings_combo_int(asettings, "AudioMixdown");
4679                         // Make sure the mixdown is valid and pick a new one if not.
4680                         audio.out.mixdown = ghb_get_best_mix(aconfig, audio.out.codec, 
4681                                                                                                         audio.out.mixdown);
4682                         audio.out.bitrate = 
4683                                 ghb_settings_combo_int(asettings, "AudioBitrate");
4684                         gint srate = ghb_settings_combo_int(asettings, "AudioSamplerate");
4685                         if (srate == 0) // 0 is same as source
4686                                 audio.out.samplerate = aconfig->in.samplerate;
4687                         else
4688                                 audio.out.samplerate = srate;
4689
4690                         audio.out.bitrate = hb_get_best_audio_bitrate(
4691                                 audio.out.codec, audio.out.bitrate, 
4692                                 audio.out.samplerate, audio.out.mixdown);
4693                 }
4694
4695                 // Add it to the jobs audio list
4696         hb_audio_add( job, &audio );
4697                 tcount++;
4698         }
4699         // I was tempted to move this up with the reset of the video quality
4700         // settings, but I suspect the settings above need to be made
4701         // first in order for hb_calc_bitrate to be accurate.
4702         if (ghb_settings_get_boolean(js, "vquality_type_target"))
4703         {
4704                 gint size;
4705                 
4706                 size = ghb_settings_get_int(js, "VideoTargetSize");
4707         job->vbitrate = hb_calc_bitrate( job, size );
4708                 job->vquality = -1.0;
4709         }
4710
4711         dest_str = ghb_settings_get_string(js, "destination");
4712         job->file = dest_str;
4713
4714         const GValue *subtitle_list;
4715         gint subtitle;
4716         gboolean force, burned, def, one_burned = FALSE;
4717         
4718         ghb_settings_set_boolean(js, "subtitle_scan", FALSE);
4719         subtitle_list = ghb_settings_get_value(js, "subtitle_list");
4720         count = ghb_array_len(subtitle_list);
4721         for (ii = 0; ii < count; ii++)
4722         {
4723                 GValue *ssettings;
4724                 gint source;
4725
4726                 ssettings = ghb_array_get_nth(subtitle_list, ii);
4727
4728                 force = ghb_settings_get_boolean(ssettings, "SubtitleForced");
4729                 burned = ghb_settings_get_boolean(ssettings, "SubtitleBurned");
4730                 def = ghb_settings_get_boolean(ssettings, "SubtitleDefaultTrack");
4731                 source = ghb_settings_get_int(ssettings, "SubtitleSource");
4732
4733                 if (source == SRTSUB)
4734                 {
4735                 hb_subtitle_config_t sub_config;
4736                         gchar *filename, *lang, *code;
4737
4738                         filename = ghb_settings_get_string(ssettings, "SrtFile");
4739                         if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
4740                         {
4741                                 continue;
4742                         }
4743                         sub_config.offset = ghb_settings_get_int(ssettings, "SrtOffset");
4744                         lang = ghb_settings_get_string(ssettings, "SrtLanguage");
4745                         code = ghb_settings_get_string(ssettings, "SrtCodeset");
4746                         strncpy(sub_config.src_filename, filename, 255);
4747                         sub_config.src_filename[255] = 0;
4748                         strncpy(sub_config.src_codeset, code, 39);
4749                         sub_config.src_codeset[39] = 0;
4750                         sub_config.force = 0;
4751                         sub_config.dest = PASSTHRUSUB;
4752                         sub_config.default_track = def;
4753
4754                         hb_srt_add( job, &sub_config, lang);
4755
4756                         g_free(filename);
4757                         g_free(lang);
4758                         g_free(code);
4759                         continue;
4760                 }
4761
4762                 subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack");
4763                 if (subtitle == -1)
4764                 {
4765                         if (!burned)
4766                         {
4767                                 job->select_subtitle_config.dest = PASSTHRUSUB;
4768                         }
4769                         else if (burned)
4770                         {
4771                                 // Only allow one subtitle to be burned into the video
4772                                 if (one_burned)
4773                                         continue;
4774                                 job->select_subtitle_config.dest = RENDERSUB;
4775                                 one_burned = TRUE;
4776                         }
4777                         job->select_subtitle_config.force = force;
4778                         job->select_subtitle_config.default_track = def;
4779                         job->indepth_scan = 1;
4780                         ghb_settings_set_boolean(js, "subtitle_scan", TRUE);
4781                 }
4782                 else if (subtitle >= 0)
4783                 {
4784                 hb_subtitle_t * subt;
4785                 hb_subtitle_config_t sub_config;
4786
4787                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
4788                         if (subt != NULL)
4789                         {
4790                                 sub_config = subt->config;
4791                                 if (!burned)
4792                                 {
4793                                         sub_config.dest = PASSTHRUSUB;
4794                                 }
4795                                 else if ( burned && canBurn(subt->source) )
4796                                 {
4797                                         // Only allow one subtitle to be burned into the video
4798                                         if (one_burned)
4799                                                 continue;
4800                                         sub_config.dest = RENDERSUB;
4801                                         one_burned = TRUE;
4802                                 }
4803                                 sub_config.force = force;
4804                                 sub_config.default_track = def;
4805                         hb_subtitle_add( job, &sub_config, subtitle );
4806                         }
4807                 }
4808         }
4809
4810         // TODO: libhb holds onto a reference to the x264opts and is not
4811         // finished with it until encoding the job is done.  But I can't
4812         // find a way to get at the job before it is removed in order to
4813         // free up the memory I am allocating here.
4814         // The short story is THIS LEAKS.
4815         x264opts = ghb_build_x264opts_string(js);
4816         
4817         if( *x264opts == '\0' )
4818         {
4819                 g_free(x264opts);
4820                 x264opts = NULL;
4821         }
4822
4823         if (job->indepth_scan == 1)
4824         {
4825                 // Subtitle scan. Look for subtitle matching audio language
4826
4827                 /*
4828                  * When subtitle scan is enabled do a fast pre-scan job
4829                  * which will determine which subtitles to enable, if any.
4830                  */
4831                 job->pass = -1;
4832                 job->indepth_scan = 1;
4833                 job->x264opts = NULL;
4834
4835                 /*
4836                  * Add the pre-scan job
4837                  */
4838                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4839                 hb_add( h, job );
4840         }
4841
4842         if( ghb_settings_get_boolean(js, "VideoTwoPass") &&
4843                 !ghb_settings_get_boolean(js, "vquality_type_constant"))
4844         {
4845                 /*
4846                  * If subtitle_scan is enabled then only turn it on
4847                  * for the second pass and then off again for the
4848                  * second.
4849                  */
4850                 job->pass = 1;
4851                 job->indepth_scan = 0;
4852
4853                 /*
4854                  * If turbo options have been selected then append them
4855                  * to the x264opts now (size includes one ':' and the '\0')
4856                  */
4857                 if( ghb_settings_get_boolean(js, "VideoTurboTwoPass") )
4858                 {
4859                         gchar *tmp_x264opts;
4860                         gchar *extra_opts;
4861                         gint badapt;
4862
4863                         badapt = ghb_lookup_badapt(x264opts);
4864                         if (badapt == 2)
4865                         {
4866                                 extra_opts = g_strdup_printf("%s", turbo_opts);
4867                         }
4868                         else
4869                         {
4870                                 extra_opts = g_strdup_printf("%s:weightb=0", turbo_opts);
4871                         }
4872         
4873                         if ( x264opts )
4874                         {
4875                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, extra_opts);
4876                         } 
4877                         else 
4878                         {
4879                                 /*
4880                                  * No x264opts to modify, but apply the turbo options
4881                                  * anyway as they may be modifying defaults
4882                                  */
4883                                 tmp_x264opts = g_strdup_printf("%s", extra_opts);
4884                         }
4885                         g_free(extra_opts);
4886
4887                         job->x264opts = tmp_x264opts;
4888                 }
4889                 else
4890                 {
4891                         job->x264opts = x264opts;
4892                 }
4893                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4894                 hb_add( h, job );
4895                 //if (job->x264opts != NULL)
4896                 //      g_free(job->x264opts);
4897
4898                 job->pass = 2;
4899                 /*
4900                  * On the second pass we turn off subtitle scan so that we
4901                  * can actually encode using any subtitles that were auto
4902                  * selected in the first pass (using the whacky select-subtitle
4903                  * attribute of the job).
4904                  */
4905                 job->indepth_scan = 0;
4906                 job->x264opts = x264opts;
4907                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4908                 hb_add( h, job );
4909                 //if (job->x264opts != NULL)
4910                 //      g_free(job->x264opts);
4911         }
4912         else
4913         {
4914                 job->x264opts = x264opts;
4915                 job->indepth_scan = 0;
4916                 job->pass = 0;
4917                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4918                 hb_add( h, job );
4919                 //if (job->x264opts != NULL)
4920                 //      g_free(job->x264opts);
4921         }
4922
4923         // clean up audio list
4924         gint num_audio_tracks = hb_list_count(job->list_audio);
4925         for(ii = 0; ii < num_audio_tracks; ii++)
4926         {
4927                 hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
4928                 hb_list_rem(job->list_audio, audio);
4929                 free(audio);
4930         }
4931
4932         // clean up subtitle list
4933         gint num_subtitle_tracks = hb_list_count(job->list_subtitle);
4934         for(ii = 0; ii < num_subtitle_tracks; ii++)
4935         {
4936                 hb_subtitle_t *subtitle = hb_list_item(job->list_subtitle, 0);
4937                 hb_list_rem(job->list_subtitle, subtitle);
4938                 free(subtitle);
4939         }
4940
4941         if (detel_str) g_free(detel_str);
4942         if (decomb_str) g_free(decomb_str);
4943         if (deint_str) g_free(deint_str);
4944         if (deblock_str) g_free(deblock_str);
4945         if (denoise_str) g_free(denoise_str);
4946         if (dest_str) g_free(dest_str);
4947 }
4948
4949 void
4950 ghb_add_job(GValue *js, gint unique_id)
4951 {
4952         // Since I'm doing a scan of the single title I want just prior 
4953         // to adding the job, there is only the one title to choose from.
4954         add_job(h_queue, js, unique_id, 0);
4955 }
4956
4957 void
4958 ghb_add_live_job(GValue *js, gint unique_id)
4959 {
4960         // Since I'm doing a scan of the single title I want just prior 
4961         // to adding the job, there is only the one title to choose from.
4962         gint titleindex = ghb_settings_combo_int(js, "title");
4963         add_job(h_scan, js, unique_id, titleindex);
4964 }
4965
4966 void
4967 ghb_remove_job(gint unique_id)
4968 {
4969     hb_job_t * job;
4970     gint ii;
4971         
4972         // Multiples passes all get the same id
4973         // remove them all.
4974         // Go backwards through list, so reordering doesn't screw me.
4975         ii = hb_count(h_queue) - 1;
4976     while ((job = hb_job(h_queue, ii--)) != NULL)
4977     {
4978         if ((job->sequence_id & 0xFFFFFF) == unique_id)
4979                         hb_rem(h_queue, job);
4980     }
4981 }
4982
4983 void
4984 ghb_start_queue()
4985 {
4986         hb_start( h_queue );
4987 }
4988
4989 void
4990 ghb_stop_queue()
4991 {
4992         hb_stop( h_queue );
4993 }
4994
4995 void
4996 ghb_start_live_encode()
4997 {
4998         hb_start( h_scan );
4999 }
5000
5001 void
5002 ghb_stop_live_encode()
5003 {
5004         hb_stop( h_scan );
5005 }
5006
5007 void
5008 ghb_pause_queue()
5009 {
5010     hb_state_t s;
5011     hb_get_state2( h_queue, &s );
5012
5013     if( s.state == HB_STATE_PAUSED )
5014     {
5015                 hb_status.queue.state &= ~GHB_STATE_PAUSED;
5016                 hb_resume( h_queue );
5017     }
5018     else
5019     {
5020                 hb_status.queue.state |= GHB_STATE_PAUSED;
5021                 hb_pause( h_queue );
5022     }
5023 }
5024
5025 static void
5026 vert_line(
5027         GdkPixbuf * pb, 
5028         guint8 r, 
5029         guint8 g, 
5030         guint8 b, 
5031         gint x, 
5032         gint y, 
5033         gint len, 
5034         gint width)
5035 {
5036         guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5037         guint8 *dst;
5038         gint ii, jj;
5039         gint channels = gdk_pixbuf_get_n_channels (pb);
5040         gint stride = gdk_pixbuf_get_rowstride (pb);
5041
5042         for (jj = 0; jj < width; jj++)
5043         {
5044                 dst = pixels + y * stride + (x+jj) * channels;
5045                 for (ii = 0; ii < len; ii++)
5046                 {
5047                         dst[0] = r;
5048                         dst[1] = g;
5049                         dst[2] = b;
5050                         dst += stride;
5051                 }
5052         }
5053 }
5054
5055 static void
5056 horz_line(
5057         GdkPixbuf * pb, 
5058         guint8 r, 
5059         guint8 g, 
5060         guint8 b, 
5061         gint x, 
5062         gint y, 
5063         gint len,
5064         gint width)
5065 {
5066         guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5067         guint8 *dst;
5068         gint ii, jj;
5069         gint channels = gdk_pixbuf_get_n_channels (pb);
5070         gint stride = gdk_pixbuf_get_rowstride (pb);
5071
5072         for (jj = 0; jj < width; jj++)
5073         {
5074                 dst = pixels + (y+jj) * stride + x * channels;
5075                 for (ii = 0; ii < len; ii++)
5076                 {
5077                         dst[0] = r;
5078                         dst[1] = g;
5079                         dst[2] = b;
5080                         dst += channels;
5081                 }
5082         }
5083 }
5084
5085 static void
5086 hash_pixbuf(
5087         GdkPixbuf * pb,
5088         gint        x,
5089         gint        y,
5090         gint        w,
5091         gint        h,
5092         gint        step,
5093         gint            orientation)
5094 {
5095         gint ii, jj;
5096         gint line_width = 8;
5097         struct
5098         {
5099                 guint8 r;
5100                 guint8 g;
5101                 guint8 b;
5102         } c[4] = 
5103         {{0x80, 0x80, 0x80},{0xC0, 0x80, 0x70},{0x80, 0xA0, 0x80},{0x70, 0x80, 0xA0}};
5104
5105         if (!orientation)
5106         {
5107                 // vertical lines
5108                 for (ii = x, jj = 0; ii+line_width < x+w; ii += step, jj++)
5109                 {
5110                         vert_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, ii, y, h, line_width);
5111                 }
5112         }
5113         else
5114         {
5115                 // horizontal lines
5116                 for (ii = y, jj = 0; ii+line_width < y+h; ii += step, jj++)
5117                 {
5118                         horz_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, x, ii, w, line_width);
5119                 }
5120         }
5121 }
5122
5123 GdkPixbuf*
5124 ghb_get_preview_image(
5125         gint titleindex, 
5126         gint index, 
5127         signal_user_data_t *ud,
5128         gint *out_width,
5129         gint *out_height)
5130 {
5131         GValue *settings;
5132         hb_title_t *title;
5133         hb_list_t  *list;
5134         
5135         settings = ud->settings;
5136         list = hb_get_titles( h_scan );
5137         if( !hb_list_count( list ) )
5138         {
5139                 /* No valid title, stop right there */
5140                 return NULL;
5141         }
5142     title = hb_list_item( list, titleindex );
5143         if (title == NULL) return NULL;
5144         if (title->job == NULL) return NULL;
5145         set_preview_job_settings(title->job, settings);
5146
5147         // hb_get_preview doesn't compensate for anamorphic, so lets
5148         // calculate scale factors
5149         gint width, height, par_width = 1, par_height = 1;
5150         gint pic_par = ghb_settings_combo_int(settings, "PicturePAR");
5151         if (pic_par)
5152         {
5153                 hb_set_anamorphic_size( title->job, &width, &height, 
5154                                                                 &par_width, &par_height );
5155         }
5156
5157         // Make sure we have a big enough buffer to receive the image from libhb
5158         gint dstWidth = title->job->width;
5159         gint dstHeight= title->job->height;
5160
5161         static guint8 *buffer = NULL;
5162         static gint bufferSize = 0;
5163         gint newSize;
5164
5165         newSize = dstWidth * dstHeight * 4;
5166         if( bufferSize < newSize )
5167         {
5168                 bufferSize = newSize;
5169                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
5170         }
5171         hb_get_preview( h_scan, title, index, buffer );
5172
5173         // Create an GdkPixbuf and copy the libhb image into it, converting it from
5174         // libhb's format something suitable.
5175         
5176         // The image data returned by hb_get_preview is 4 bytes per pixel, 
5177         // BGRA format. Alpha is ignored.
5178
5179         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
5180         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
5181         
5182         guint32 *src = (guint32*)buffer;
5183         guint8 *dst = pixels;
5184
5185         gint ii, jj;
5186         gint channels = gdk_pixbuf_get_n_channels (preview);
5187         gint stride = gdk_pixbuf_get_rowstride (preview);
5188         guint8 *tmp;
5189
5190         for (ii = 0; ii < dstHeight; ii++)
5191         {
5192                 tmp = dst;
5193                 for (jj = 0; jj < dstWidth; jj++)
5194                 {
5195                         tmp[0] = src[0] >> 16;
5196                         tmp[1] = src[0] >> 8;
5197                         tmp[2] = src[0] >> 0;
5198                         tmp += channels;
5199                         src++;
5200                 }
5201                 dst += stride;
5202         }
5203         gint w = ghb_settings_get_int(settings, "scale_width");
5204         gint h = ghb_settings_get_int(settings, "scale_height");
5205         ghb_par_scale(ud, &w, &h, par_width, par_height);
5206
5207         gint c0, c1, c2, c3;
5208         c0 = ghb_settings_get_int(settings, "PictureTopCrop");
5209         c1 = ghb_settings_get_int(settings, "PictureBottomCrop");
5210         c2 = ghb_settings_get_int(settings, "PictureLeftCrop");
5211         c3 = ghb_settings_get_int(settings, "PictureRightCrop");
5212
5213         gdouble xscale = (gdouble)w / (gdouble)(title->width - c2 - c3);
5214         gdouble yscale = (gdouble)h / (gdouble)(title->height - c0 - c1);
5215         
5216         ghb_par_scale(ud, &dstWidth, &dstHeight, par_width, par_height);
5217         *out_width = w;
5218         *out_height = h;
5219         if (ghb_settings_get_boolean(settings, "reduce_hd_preview"))
5220         {
5221                 GdkScreen *ss;
5222                 gint s_w, s_h;
5223                 gint orig_w, orig_h;
5224                 gint factor = 80;
5225
5226                 if (ghb_settings_get_boolean(settings, "preview_fullscreen"))
5227                 {
5228                         factor = 100;
5229                 }
5230                 ss = gdk_screen_get_default();
5231                 s_w = gdk_screen_get_width(ss);
5232                 s_h = gdk_screen_get_height(ss);
5233                 orig_w = dstWidth;
5234                 orig_h = dstHeight;
5235
5236                 if (dstWidth > s_w * factor / 100)
5237                 {
5238                         dstWidth = s_w * factor / 100;
5239                         dstHeight = dstHeight * dstWidth / orig_w;
5240                 }
5241                 if (dstHeight > s_h * factor / 100)
5242                 {
5243                         dstHeight = s_h * factor / 100;
5244                         dstWidth = dstWidth * dstHeight / orig_h;
5245                 }
5246                 xscale *= (gdouble)dstWidth / orig_w;
5247                 yscale *= (gdouble)dstHeight / orig_h;
5248                 w *= (gdouble)dstWidth / orig_w;
5249                 h *= (gdouble)dstHeight / orig_h;
5250         }
5251         GdkPixbuf *scaled_preview;
5252         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
5253         if (ghb_settings_get_boolean(settings, "show_crop"))
5254         {
5255                 c0 *= yscale;
5256                 c1 *= yscale;
5257                 c2 *= xscale;
5258                 c3 *= xscale;
5259                 // Top
5260                 hash_pixbuf(scaled_preview, c2, 0, w, c0, 32, 0);
5261                 // Bottom
5262                 hash_pixbuf(scaled_preview, c2, dstHeight-c1, w, c1, 32, 0);
5263                 // Left
5264                 hash_pixbuf(scaled_preview, 0, c0, c2, h, 32, 1);
5265                 // Right
5266                 hash_pixbuf(scaled_preview, dstWidth-c3, c0, c3, h, 32, 1);
5267         }
5268         g_object_unref (preview);
5269         return scaled_preview;
5270 }
5271
5272 static void
5273 sanitize_volname(gchar *name)
5274 {
5275         gchar *a, *b;
5276
5277         a = b = name;
5278         while (*b)
5279         {
5280                 switch(*b)
5281                 {
5282                 case '<':
5283                         b++;
5284                         break;
5285                 case '>':
5286                         b++;
5287                         break;
5288                 default:
5289                         *a = *b;
5290                         a++; b++;
5291                         break;
5292                 }
5293         }
5294         *a = 0;
5295 }
5296
5297 gchar*
5298 ghb_dvd_volname(const gchar *device)
5299 {
5300         gchar *name;
5301         name = hb_dvd_name((gchar*)device);
5302         if (name != NULL && name[0] != 0)
5303         {
5304                 name = g_strdup(name);
5305                 sanitize_volname(name);
5306                 return name;
5307         }
5308         return NULL;
5309 }