1 /***************************************************************************
4 * Fri Mar 28 10:38:44 2008
5 * Copyright 2008 John Stebbins
6 * <john at stebbins dot name>
7 ****************************************************************************/
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.
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.
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
29 #include <glib/gstdio.h>
30 #include "hb-backend.h"
32 #include "callbacks.h"
33 #include "subtitlehandler.h"
34 #include "audiohandler.h"
35 #include "x264handler.h"
43 const gchar *shortOpt;
54 static gchar **index_str = NULL;
55 static gint index_str_size = 0;
58 index_str_init(gint max_index)
62 if (max_index+1 > index_str_size)
64 index_str = realloc(index_str, (max_index+1) * sizeof(char*));
65 for (ii = index_str_size; ii <= max_index; ii++)
67 index_str[ii] = g_strdup_printf("%d", ii);
69 index_str_size = max_index + 1;
73 static options_map_t d_point_to_point_opts[] =
75 {"Chapters:", "chapter", 0, "0"},
76 {"Seconds:", "time", 1, "1"},
77 {"Frames:", "frame", 2, "2"},
79 combo_opts_t point_to_point_opts =
81 sizeof(d_point_to_point_opts)/sizeof(options_map_t),
85 static options_map_t d_when_complete_opts[] =
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"},
93 combo_opts_t when_complete_opts =
95 sizeof(d_when_complete_opts)/sizeof(options_map_t),
99 static options_map_t d_par_opts[] =
101 {"Off", "0", 0, "0"},
102 {"Strict", "1", 1, "1"},
103 {"Loose", "2", 2, "2"},
104 {"Custom", "3", 3, "3"},
106 combo_opts_t par_opts =
108 sizeof(d_par_opts)/sizeof(options_map_t),
112 static options_map_t d_alignment_opts[] =
117 {"16", "16", 16, "16"},
119 combo_opts_t alignment_opts =
121 sizeof(d_alignment_opts)/sizeof(options_map_t),
125 static options_map_t d_logging_opts[] =
131 combo_opts_t logging_opts =
133 sizeof(d_logging_opts)/sizeof(options_map_t),
137 static options_map_t d_log_longevity_opts[] =
139 {"Week", "week", 7, "7"},
140 {"Month", "month", 30, "30"},
141 {"Year", "year", 365, "365"},
142 {"Immortal", "immortal", 366, "366"},
144 combo_opts_t log_longevity_opts =
146 sizeof(d_log_longevity_opts)/sizeof(options_map_t),
150 static options_map_t d_appcast_update_opts[] =
152 {"Never", "never", 0, "never"},
153 {"Daily", "daily", 1, "daily"},
154 {"Weekly", "weekly", 2, "weekly"},
155 {"Monthly", "monthly", 3, "monthly"},
157 combo_opts_t appcast_update_opts =
159 sizeof(d_appcast_update_opts)/sizeof(options_map_t),
160 d_appcast_update_opts
163 static options_map_t d_vqual_granularity_opts[] =
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"},
170 combo_opts_t vqual_granularity_opts =
172 sizeof(d_vqual_granularity_opts)/sizeof(options_map_t),
173 d_vqual_granularity_opts
176 static options_map_t d_container_opts[] =
178 {"MKV", "mkv", HB_MUX_MKV, "mkv"},
179 {"MP4", "mp4", HB_MUX_MP4, "mp4"},
181 combo_opts_t container_opts =
183 sizeof(d_container_opts)/sizeof(options_map_t),
187 static options_map_t d_detel_opts[] =
189 {"Off", "off", 0, ""},
190 {"Custom", "custom", 1, ""},
191 {"Default","default",2, NULL},
193 combo_opts_t detel_opts =
195 sizeof(d_detel_opts)/sizeof(options_map_t),
199 static options_map_t d_decomb_opts[] =
201 {"Off", "off", 0, ""},
202 {"Custom", "custom", 1, ""},
203 {"Default","default",2, NULL},
205 combo_opts_t decomb_opts =
207 sizeof(d_decomb_opts)/sizeof(options_map_t),
211 static options_map_t d_deint_opts[] =
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"},
219 combo_opts_t deint_opts =
221 sizeof(d_deint_opts)/sizeof(options_map_t),
225 static options_map_t d_denoise_opts[] =
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"},
233 combo_opts_t denoise_opts =
235 sizeof(d_denoise_opts)/sizeof(options_map_t),
239 static options_map_t d_vcodec_opts[] =
241 {"H.264 (x264)", "x264", HB_VCODEC_X264, ""},
242 {"MPEG-4 (FFmpeg)", "ffmpeg", HB_VCODEC_FFMPEG, ""},
243 {"VP3 (Theora)", "theora", HB_VCODEC_THEORA, ""},
245 combo_opts_t vcodec_opts =
247 sizeof(d_vcodec_opts)/sizeof(options_map_t),
251 static options_map_t d_acodec_opts[] =
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"},
261 combo_opts_t acodec_opts =
263 sizeof(d_acodec_opts)/sizeof(options_map_t),
267 static options_map_t d_direct_opts[] =
269 {"None", "none", 0, "none"},
270 {"Spatial", "spatial", 1, "spatial"},
271 {"Temporal", "temporal", 2, "temporal"},
272 {"Automatic", "auto", 3, "auto"},
274 combo_opts_t direct_opts =
276 sizeof(d_direct_opts)/sizeof(options_map_t),
280 static options_map_t d_badapt_opts[] =
282 {"Off", "0", 0, "0"},
283 {"Fast", "1", 1, "1"},
284 {"Optimal", "2", 2, "2"},
286 combo_opts_t badapt_opts =
288 sizeof(d_badapt_opts)/sizeof(options_map_t),
292 static options_map_t d_bpyramid_opts[] =
294 {"Off", "none", 0, "none"},
295 {"Strict", "strict", 1, "strict"},
296 {"Normal", "normal", 2, "normal"},
298 combo_opts_t bpyramid_opts =
300 sizeof(d_bpyramid_opts)/sizeof(options_map_t),
304 static options_map_t d_weightp_opts[] =
306 {"Off", "0", 0, "0"},
307 {"Blind", "1", 1, "1"},
308 {"Smart", "2", 2, "2"},
310 combo_opts_t weightp_opts =
312 sizeof(d_weightp_opts)/sizeof(options_map_t),
316 static options_map_t d_me_opts[] =
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"},
324 combo_opts_t me_opts =
326 sizeof(d_me_opts)/sizeof(options_map_t),
330 static options_map_t d_subme_opts[] =
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"},
344 combo_opts_t subme_opts =
346 sizeof(d_subme_opts)/sizeof(options_map_t),
350 static options_map_t d_analyse_opts[] =
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"},
358 combo_opts_t analyse_opts =
360 sizeof(d_analyse_opts)/sizeof(options_map_t),
364 static options_map_t d_trellis_opts[] =
366 {"Off", "0", 0, "0"},
367 {"Encode only", "1", 1, "1"},
368 {"Always", "2", 2, "2"},
370 combo_opts_t trellis_opts =
372 sizeof(d_trellis_opts)/sizeof(options_map_t),
376 combo_opts_t subtitle_opts =
382 combo_opts_t title_opts =
388 combo_opts_t audio_track_opts =
400 combo_name_map_t combo_name_map[] =
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},
432 const gchar *srt_codeset_table[] =
471 #define SRT_TABLE_SIZE (sizeof(srt_codeset_table)/ sizeof(char*)-1)
474 typedef struct iso639_lang_t
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) */
484 const iso639_lang_t ghb_language_table[] =
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}
674 #define LANG_TABLE_SIZE (sizeof(ghb_language_table)/ sizeof(iso639_lang_t)-1)
676 static void audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name);
679 del_tree(const gchar *name, gboolean del_top)
683 if (g_file_test(name, G_FILE_TEST_IS_DIR))
685 GDir *gdir = g_dir_open(name, 0, NULL);
686 file = g_dir_read_name(gdir);
690 path = g_strdup_printf("%s/%s", name, file);
691 del_tree(path, TRUE);
693 file = g_dir_read_name(gdir);
708 return hb_get_version(NULL);
713 signal_user_data_t *ud,
721 gint vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
730 *step = ghb_settings_combo_double(ud->settings,
731 "VideoQualityGranularity");
732 if (*step == 0.2 || *step == 0.5)
734 else if (*step == 0.25)
739 case HB_VCODEC_FFMPEG:
747 case HB_VCODEC_THEORA:
766 find_combo_entry(combo_opts_t *opts, const GValue *gval)
770 if (G_VALUE_TYPE(gval) == G_TYPE_STRING)
773 str = ghb_value_string(gval);
774 for (ii = 0; ii < opts->count; ii++)
776 if (strcmp(opts->map[ii].shortOpt, str) == 0)
784 else if (G_VALUE_TYPE(gval) == G_TYPE_DOUBLE)
787 val = ghb_value_double(gval);
788 for (ii = 0; ii < opts->count; ii++)
790 if (opts->map[ii].ivalue == val)
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)
802 val = ghb_value_int64(gval);
803 for (ii = 0; ii < opts->count; ii++)
805 if ((gint64)opts->map[ii].ivalue == val)
816 lookup_generic_string(combo_opts_t *opts, const GValue *gval)
819 const gchar *result = "";
821 ii = find_combo_entry(opts, gval);
822 if (ii < opts->count)
824 result = opts->map[ii].svalue;
830 lookup_generic_int(combo_opts_t *opts, const GValue *gval)
835 ii = find_combo_entry(opts, gval);
836 if (ii < opts->count)
838 result = opts->map[ii].ivalue;
844 lookup_generic_double(combo_opts_t *opts, const GValue *gval)
849 ii = find_combo_entry(opts, gval);
850 if (ii < opts->count)
852 result = opts->map[ii].ivalue;
858 lookup_generic_option(combo_opts_t *opts, const GValue *gval)
861 const gchar *result = "";
863 ii = find_combo_entry(opts, gval);
864 if (ii < opts->count)
866 result = opts->map[ii].option;
872 lookup_mix_int(const GValue *mix)
878 if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
880 gchar * str = ghb_value_string(mix);
881 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
883 if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
885 result = hb_audio_mixdowns[ii].amixdown;
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)
895 gint val = ghb_value_int(mix);
896 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
898 if (hb_audio_mixdowns[ii].amixdown == val)
900 result = hb_audio_mixdowns[ii].amixdown;
909 lookup_mix_option(const GValue *mix)
912 gchar *result = "None";
915 if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
917 gchar *str = ghb_value_string(mix);
918 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
920 if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
922 result = hb_audio_mixdowns[ii].human_readable_name;
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)
932 gint val = ghb_value_int(mix);
933 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
935 if (hb_audio_mixdowns[ii].amixdown == val)
937 result = hb_audio_mixdowns[ii].human_readable_name;
946 lookup_mix_string(const GValue *mix)
949 gchar *result = "None";
952 if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
954 gchar *str = ghb_value_string(mix);
955 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
957 if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
959 result = hb_audio_mixdowns[ii].short_name;
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)
969 gint val = ghb_value_int(mix);
970 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
972 if (hb_audio_mixdowns[ii].amixdown == val)
974 result = hb_audio_mixdowns[ii].short_name;
983 lookup_video_rate_int(const GValue *vrate)
989 str = ghb_value_string(vrate);
990 for (ii = 0; ii < hb_video_rates_count; ii++)
992 if (strcmp(hb_video_rates[ii].string, str) == 0)
994 result = hb_video_rates[ii].rate;
999 // Default to "same as source"
1004 lookup_video_rate_option(const GValue *vrate)
1008 const gchar *result = "Same as source";
1010 str = ghb_value_string(vrate);
1011 for (ii = 0; ii < hb_video_rates_count; ii++)
1013 if (strcmp(hb_video_rates[ii].string, str) == 0)
1015 result = hb_video_rates[ii].string;
1020 // Default to "same as source"
1025 lookup_audio_rate_int(const GValue *rate)
1030 if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
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++)
1037 if (strcmp(hb_audio_rates[ii].string, str) == 0)
1039 result = hb_audio_rates[ii].rate;
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)
1049 for (ii = 0; ii < hb_audio_rates_count; ii++)
1051 gint val = ghb_value_int(rate);
1052 if (val == hb_audio_rates[ii].rate)
1054 result = hb_audio_rates[ii].rate;
1063 lookup_audio_rate_option(const GValue *rate)
1066 const gchar *result = "Same as source";
1068 if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
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++)
1075 if (strcmp(hb_audio_rates[ii].string, str) == 0)
1077 result = hb_audio_rates[ii].string;
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)
1087 for (ii = 0; ii < hb_audio_rates_count; ii++)
1089 gint val = ghb_value_int(rate);
1090 if (val == hb_audio_rates[ii].rate)
1092 result = hb_audio_rates[ii].string;
1101 ghb_find_closest_audio_rate(gint rate)
1107 for (ii = 0; ii < hb_audio_rates_count; ii++)
1109 if (rate <= hb_audio_rates[ii].rate)
1111 result = hb_audio_rates[ii].rate;
1118 hb_rate_t *ghb_audio_bitrates;
1119 int ghb_audio_bitrates_count;
1122 lookup_audio_bitrate_int(const GValue *rate)
1127 if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
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++)
1134 if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
1136 result = ghb_audio_bitrates[ii].rate;
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)
1146 gint val = ghb_value_int(rate);
1147 for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
1149 if (ghb_audio_bitrates[ii].rate == val)
1151 result = ghb_audio_bitrates[ii].rate;
1160 lookup_audio_bitrate_option(const GValue *rate)
1163 const gchar *result = "Same as source";
1165 if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
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++)
1172 if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
1174 result = ghb_audio_bitrates[ii].string;
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)
1184 gint val = ghb_value_int(rate);
1185 for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
1187 if (ghb_audio_bitrates[ii].rate == val)
1189 result = ghb_audio_bitrates[ii].string;
1198 lookup_audio_lang_int(const GValue *rate)
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++)
1209 if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
1220 lookup_audio_lang_option(const GValue *rate)
1224 const gchar *result = "Same as source";
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++)
1231 if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
1233 if (ghb_language_table[ii].native_name[0] != 0)
1234 result = ghb_language_table[ii].native_name;
1236 result = ghb_language_table[ii].eng_name;
1245 ghb_lookup_acodec_value(gint val)
1247 GValue *value = NULL;
1250 for (ii = 0; ii < acodec_opts.count; ii++)
1252 if ((int)acodec_opts.map[ii].ivalue == val)
1254 value = ghb_string_value_new(acodec_opts.map[ii].shortOpt);
1258 value = ghb_string_value_new("auto");
1263 get_amix_value(gint val)
1265 GValue *value = NULL;
1268 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
1270 if (hb_audio_mixdowns[ii].amixdown == val)
1272 value = ghb_string_value_new(hb_audio_mixdowns[ii].short_name);
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;
1283 extern void hb_get_temporary_directory(char path[512]);
1290 hb_get_temporary_directory(dir);
1291 return g_strdup(dir);
1295 ghb_hb_cleanup(gboolean partial)
1299 hb_get_temporary_directory(dir);
1300 del_tree(dir, !partial);
1304 ghb_subtitle_track_source(signal_user_data_t *ud, gint track)
1312 titleindex = ghb_settings_combo_int(ud->settings, "title");
1318 hb_subtitle_t * sub;
1320 if (h_scan == NULL) return VOBSUB;
1321 list = hb_get_titles( h_scan );
1322 if( !hb_list_count( list ) )
1324 /* No valid title, stop right there */
1327 title = hb_list_item( list, titleindex );
1328 if (title == NULL) return VOBSUB; // Bad titleindex
1329 sub = hb_list_item( title->list_subtitle, track);
1337 ghb_subtitle_source_name(gint source)
1339 const gchar * name = "Unknown";
1368 ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track)
1371 const gchar * name = "Unknown";
1384 titleindex = ghb_settings_combo_int(ud->settings, "title");
1390 hb_subtitle_t * sub;
1394 list = hb_get_titles( h_scan );
1395 if( !hb_list_count( list ) )
1398 title = hb_list_item( list, titleindex );
1402 sub = hb_list_item( title->list_subtitle, track);
1405 name = ghb_subtitle_source_name(sub->source);
1413 ghb_subtitle_track_lang(signal_user_data_t *ud, gint track)
1417 titleindex = ghb_settings_combo_int(ud->settings, "title");
1421 return ghb_get_user_audio_lang(ud, titleindex, 0);
1427 hb_subtitle_t * sub;
1432 list = hb_get_titles( h_scan );
1433 if( !hb_list_count( list ) )
1435 /* No valid title, stop right there */
1438 title = hb_list_item( list, titleindex );
1439 if (title == NULL) // Bad titleindex
1441 sub = hb_list_item( title->list_subtitle, track);
1443 return g_strdup(sub->iso639_2);
1446 return g_strdup("und");
1450 ghb_get_title_number(gint titleindex)
1455 if (h_scan == NULL) return 1;
1456 list = hb_get_titles( h_scan );
1457 if( !hb_list_count( list ) )
1459 /* No valid title, stop right there */
1462 title = hb_list_item( list, titleindex );
1463 if (title == NULL) return 1; // Bad titleindex
1464 return title->index;
1467 static hb_audio_config_t*
1468 get_hb_audio(hb_handle_t *h, gint titleindex, gint track)
1472 hb_audio_config_t *audio = NULL;
1474 if (h == NULL) return NULL;
1475 list = hb_get_titles( h );
1476 if( !hb_list_count( list ) )
1478 /* No valid title, stop right there */
1481 title = hb_list_item( list, titleindex );
1482 if (title == NULL) return NULL; // Bad titleindex
1483 if (!hb_list_count(title->list_audio))
1487 audio = (hb_audio_config_t *)hb_list_audio_config_item(title->list_audio, track);
1492 search_rates(hb_rate_t *rates, gint rate, gint count)
1495 for (ii = 0; ii < count; ii++)
1497 if (rates[ii].rate == rate)
1503 static gboolean find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter);
1505 static GtkListStore*
1506 get_combo_box_store(GtkBuilder *builder, const gchar *name)
1509 GtkListStore *store;
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));
1519 grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean grey)
1521 GtkListStore *store;
1524 store = get_combo_box_store(builder, name);
1525 if (find_combo_item_by_int(GTK_TREE_MODEL(store), value, &iter))
1527 gtk_list_store_set(store, &iter,
1534 ghb_grey_combo_options(GtkBuilder *builder)
1537 gint container, track, titleindex, acodec;
1538 hb_audio_config_t *aconfig = NULL;
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);
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);
1560 gboolean allow_dca = TRUE;
1561 allow_dca = (container != HB_MUX_MP4);
1563 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, FALSE);
1565 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, FALSE);
1567 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE);
1569 if (aconfig && aconfig->in.codec != HB_ACODEC_AC3)
1571 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, TRUE);
1573 if (aconfig && aconfig->in.codec != HB_ACODEC_DCA)
1575 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE);
1577 grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, FALSE);
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)
1586 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, TRUE);
1587 grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, TRUE);
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;
1596 allow_6ch = acodec & ~HB_ACODEC_LAME;
1599 gint best = hb_get_best_mixdown(acodec, aconfig->in.channel_layout, 0);
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;
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);
1614 ghb_get_best_mix(hb_audio_config_t *aconfig, gint acodec, gint mix)
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 );
1622 // Set up the model for the combo box
1624 init_combo_box(GtkBuilder *builder, const gchar *name)
1627 GtkListStore *store;
1628 GtkCellRenderer *cell;
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));
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));
1645 if (GTK_WIDGET_TYPE(combo) == GTK_TYPE_COMBO_BOX)
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);
1654 { // Combo box entry
1655 gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(combo), 0);
1660 audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
1663 GtkListStore *store;
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>",
1679 for (ii = 0; ii < count; ii++)
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,
1686 2, rates[ii].string,
1687 3, (gdouble)rates[ii].rate,
1688 4, rates[ii].string,
1695 video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
1698 GtkListStore *store;
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",
1713 for (ii = 0; ii < count; ii++)
1717 if (strcmp(rates[ii].string, "23.976") == 0)
1719 desc = "(NTSC Film)";
1721 else if (strcmp(rates[ii].string, "25") == 0)
1723 desc = "(PAL Film/Video)";
1725 else if (strcmp(rates[ii].string, "29.97") == 0)
1727 desc = "(NTSC Video)";
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,
1734 2, rates[ii].string,
1735 3, (gdouble)rates[ii].rate,
1736 4, rates[ii].string,
1743 mix_opts_set(GtkBuilder *builder, const gchar *name)
1746 GtkListStore *store;
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>",
1761 for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
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,
1769 2, hb_audio_mixdowns[ii].short_name,
1770 3, (gdouble)hb_audio_mixdowns[ii].amixdown,
1771 4, hb_audio_mixdowns[ii].internal_name,
1778 srt_codeset_opts_set(GtkBuilder *builder, const gchar *name)
1781 GtkListStore *store;
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++)
1789 gtk_list_store_append(store, &iter);
1790 gtk_list_store_set(store, &iter,
1791 0, srt_codeset_table[ii],
1793 2, srt_codeset_table[ii],
1795 4, srt_codeset_table[ii],
1798 GtkComboBoxEntry *cbe;
1800 cbe = GTK_COMBO_BOX_ENTRY(GHB_WIDGET(builder, name));
1801 //gtk_combo_box_entry_set_text_column(cbe, 0);
1805 language_opts_set(GtkBuilder *builder, const gchar *name)
1808 GtkListStore *store;
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++)
1818 if (ghb_language_table[ii].native_name[0] != 0)
1819 lang = ghb_language_table[ii].native_name;
1821 lang = ghb_language_table[ii].eng_name;
1823 gtk_list_store_append(store, &iter);
1824 gtk_list_store_set(store, &iter,
1827 2, ghb_language_table[ii].iso639_2,
1829 4, ghb_language_table[ii].iso639_1,
1834 static gchar **titles = NULL;
1837 title_opts_set(GtkBuilder *builder, const gchar *name)
1840 GtkListStore *store;
1841 hb_list_t * list = NULL;
1842 hb_title_t * title = NULL;
1846 g_debug("title_opts_set ()\n");
1847 store = get_combo_box_store(builder, name);
1848 gtk_list_store_clear(store);
1851 list = hb_get_titles( h_scan );
1852 count = hb_list_count( list );
1853 if (count > 100) count = 100;
1855 if (titles) g_strfreev(titles);
1856 if (title_opts.map) g_free(title_opts.map);
1859 title_opts.count = count;
1860 title_opts.map = g_malloc(count*sizeof(options_map_t));
1861 titles = g_malloc((count+1) * sizeof(gchar*));
1865 title_opts.count = 1;
1866 title_opts.map = g_malloc(sizeof(options_map_t));
1871 // No titles. Fill in a default.
1872 gtk_list_store_append(store, &iter);
1873 gtk_list_store_set(store, &iter,
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";
1886 for (ii = 0; ii < count; ii++)
1888 title = (hb_title_t*)hb_list_item(list, ii);
1889 if (title->type == HB_STREAM_TYPE)
1891 if (title->duration != 0)
1893 titles[ii] = g_strdup_printf ("%d - %02dh%02dm%02ds - %s",
1894 title->index, title->hours, title->minutes, title->seconds,
1899 titles[ii] = g_strdup_printf ("%d - %s",
1900 title->index, title->name);
1905 if (title->duration != 0)
1907 titles[ii] = g_strdup_printf ("%d - %02dh%02dm%02ds",
1908 title->index, title->hours, title->minutes, title->seconds);
1912 titles[ii] = g_strdup_printf ("%d - Unknown Length",
1916 gtk_list_store_append(store, &iter);
1917 gtk_list_store_set(store, &iter,
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];
1933 find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter)
1936 gboolean foundit = FALSE;
1938 if (gtk_tree_model_get_iter_first (store, iter))
1942 gtk_tree_model_get(store, iter, 3, &ivalue, -1);
1943 if (value == (gint)ivalue)
1948 } while (gtk_tree_model_iter_next (store, iter));
1954 audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1957 GtkListStore *store;
1958 hb_list_t * list = NULL;
1959 hb_title_t * title = NULL;
1960 hb_audio_config_t * audio;
1965 g_debug("audio_track_opts_set ()\n");
1966 store = get_combo_box_store(builder, name);
1967 gtk_list_store_clear(store);
1970 list = hb_get_titles( h_scan );
1971 title = (hb_title_t*)hb_list_item( list, titleindex );
1974 count = hb_list_count( title->list_audio );
1977 if (count > 100) count = 100;
1978 if (audio_track_opts.map) g_free(audio_track_opts.map);
1981 audio_track_opts.count = count;
1982 audio_track_opts.map = g_malloc(count*sizeof(options_map_t));
1986 audio_track_opts.count = 1;
1987 audio_track_opts.map = g_malloc(sizeof(options_map_t));
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>",
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";
2006 index_str_init(count-1);
2007 for (ii = 0; ii < count; ii++)
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,
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];
2028 subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
2031 GtkListStore *store;
2032 hb_list_t * list = NULL;
2033 hb_title_t * title = NULL;
2034 hb_subtitle_t * subtitle;
2036 static char ** options = NULL;
2038 g_debug("subtitle_track_opts_set ()\n");
2039 store = get_combo_box_store(builder, name);
2040 gtk_list_store_clear(store);
2043 list = hb_get_titles( h_scan );
2044 title = (hb_title_t*)hb_list_item( list, titleindex );
2047 count = hb_list_count( title->list_subtitle );
2050 if (count > 100) count = 100;
2051 if (subtitle_opts.map) g_free(subtitle_opts.map);
2054 subtitle_opts.count = count+1;
2055 subtitle_opts.map = g_malloc((count+1)*sizeof(options_map_t));
2059 subtitle_opts.count = LANG_TABLE_SIZE+1;
2060 subtitle_opts.map = g_malloc((LANG_TABLE_SIZE+1)*sizeof(options_map_t));
2062 gtk_list_store_append(store, &iter);
2063 gtk_list_store_set(store, &iter,
2064 0, "Foreign Audio Search",
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";
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++)
2082 subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
2083 options[ii] = g_strdup_printf("%d - %s (%s)", ii+1,
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,
2096 4, subtitle->iso639_2,
2099 options[count] = NULL;
2103 index_str_init(LANG_TABLE_SIZE-1);
2104 for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
2108 if (ghb_language_table[ii].native_name[0] != 0)
2109 lang = ghb_language_table[ii].native_name;
2111 lang = ghb_language_table[ii].eng_name;
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,
2123 4, ghb_language_table[ii].iso639_2,
2136 gint titleindex = 0;
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++)
2149 title = (hb_title_t*)hb_list_item(list, ii);
2150 if (title->index == feature)
2159 ghb_get_source_audio_lang(gint titleindex, gint track)
2163 hb_audio_config_t * audio;
2166 g_debug("ghb_lookup_1st_audio_lang ()\n");
2169 list = hb_get_titles( h_scan );
2170 title = (hb_title_t*)hb_list_item( list, titleindex );
2173 if (hb_list_count( title->list_audio ) <= track)
2176 audio = hb_list_audio_config_item(title->list_audio, track);
2180 lang = g_strdup(audio->lang.iso639_2);
2185 get_track_used(gint acodec, GHashTable *track_indices, gint count)
2189 used = g_hash_table_lookup(track_indices, &acodec);
2194 used = g_malloc0(count * sizeof(gboolean));
2195 key = g_malloc(sizeof(gint));
2197 g_hash_table_insert(track_indices, key, used);
2203 ghb_find_audio_track(
2207 gint fallback_acodec,
2208 GHashTable *track_indices)
2212 hb_audio_config_t * audio;
2217 gboolean *used = NULL;
2218 gboolean *passthru_used;
2220 gint passthru_acodec;
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 );
2230 count = hb_list_count( title->list_audio );
2232 if (count > 10) count = 10;
2233 // Try to find an item that matches the preferred language and
2234 // the passthru codec type
2236 passthru = (acodec & HB_ACODEC_PASS_FLAG) != 0;
2239 for (ii = 0; ii < count; ii++)
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)
2247 used = get_track_used(passthru_acodec, track_indices, count);
2248 // Has the track already been used with this codec?
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)))
2260 if (channels > max_chan)
2263 max_chan = channels;
2267 try_acodec = fallback_acodec;
2271 try_acodec = acodec;
2278 // Try to find an item that matches the preferred language
2280 used = get_track_used(try_acodec, track_indices, count);
2281 for (ii = 0; ii < count; ii++)
2283 // Has the track already been used with this codec?
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)
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])
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)))
2303 if (channels > max_chan)
2306 max_chan = channels;
2315 // Try to fine an item that does not match the preferred language and
2316 // matches the passthru codec type
2320 for (ii = 0; ii < count; ii++)
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)
2328 used = get_track_used(passthru_acodec, track_indices, count);
2329 // Has the track already been used with this codec?
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)
2339 if (channels > max_chan)
2342 max_chan = channels;
2346 try_acodec = fallback_acodec;
2350 try_acodec = acodec;
2357 // Try to fine an item that does not match the preferred language
2359 used = get_track_used(try_acodec, track_indices, count);
2360 for (ii = 0; ii < count; ii++)
2362 // Has the track already been used with this codec?
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)
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])
2377 // Find a track that is not visually impaired or dirctor's commentary
2378 if (audio->lang.type < 2)
2380 if (channels > max_chan)
2383 max_chan = channels;
2392 // Last ditch, anything goes
2393 for (ii = 0; ii < count; ii++)
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)
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])
2405 // Has the track already been used with this codec?
2420 ghb_find_pref_subtitle_track(const gchar *lang)
2423 count = subtitle_opts.count;
2424 for (ii = 0; ii < count; ii++)
2426 if (strcmp(lang, subtitle_opts.map[ii].svalue) == 0)
2428 return subtitle_opts.map[ii].ivalue;
2435 ghb_find_cc_track(gint titleindex)
2439 hb_subtitle_t * subtitle;
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 );
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++)
2452 subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
2453 if (subtitle->source == CC608SUB || subtitle->source == CC708SUB)
2461 canForce(int source)
2463 return (source == VOBSUB);
2469 return (source == VOBSUB || source == SSASUB);
2473 ghb_find_subtitle_track(
2479 GHashTable * track_indices)
2483 hb_subtitle_t * subtitle;
2487 g_debug("find_subtitle_track ()\n");
2488 if (strcmp(lang, "auto") == 0)
2490 if (h_scan == NULL) return -1;
2491 list = hb_get_titles( h_scan );
2492 title = (hb_title_t*)hb_list_item( list, titleindex );
2495 count = hb_list_count( title->list_subtitle );
2496 used = g_hash_table_lookup(track_indices, lang);
2499 used = g_malloc0(count * sizeof(gboolean));
2500 g_hash_table_insert(track_indices, g_strdup(lang), used);
2502 // Try to find an item that matches the preferred language and source
2503 for (ii = 0; ii < count; ii++)
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)))
2517 // Try to find an item that matches the preferred language
2518 for (ii = 0; ii < count; ii++)
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)))
2538 generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
2541 GtkListStore *store;
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++)
2550 gtk_list_store_append(store, &iter);
2551 gtk_list_store_set(store, &iter,
2552 0, opts->map[ii].option,
2554 2, opts->map[ii].shortOpt,
2555 3, opts->map[ii].ivalue,
2556 4, opts->map[ii].svalue,
2562 small_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
2565 GtkListStore *store;
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++)
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,
2580 2, opts->map[ii].shortOpt,
2581 3, opts->map[ii].ivalue,
2582 4, opts->map[ii].svalue,
2589 find_combo_table(const gchar *name)
2593 for (ii = 0; combo_name_map[ii].name != NULL; ii++)
2595 if (strcmp(name, combo_name_map[ii].name) == 0)
2597 return combo_name_map[ii].opts;
2604 ghb_lookup_combo_int(const gchar *name, const GValue *gval)
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);
2622 return lookup_generic_int(find_combo_table(name), gval);
2624 g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2629 ghb_lookup_combo_double(const gchar *name, const GValue *gval)
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);
2647 return lookup_generic_double(find_combo_table(name), gval);
2649 g_warning("ghb_lookup_combo_double() couldn't find %s", name);
2654 ghb_lookup_combo_option(const gchar *name, const GValue *gval)
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);
2672 return lookup_generic_option(find_combo_table(name), gval);
2674 g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2679 ghb_lookup_combo_string(const gchar *name, const GValue *gval)
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);
2697 return lookup_generic_string(find_combo_table(name), gval);
2699 g_warning("ghb_lookup_combo_int() couldn't find %s", name);
2704 ghb_update_ui_combo_box(
2705 signal_user_data_t *ud,
2710 GtkComboBox *combo = NULL;
2712 gint handler_id = 0;
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);
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);
2729 // This should also always succeed
2730 g_signal_handler_block ((gpointer)combo, handler_id);
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);
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);
2793 generic_opts_set(ud->builder, name, find_combo_table(name));
2797 g_signal_handler_unblock ((gpointer)combo, handler_id);
2802 init_ui_combo_boxes(GtkBuilder *builder)
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++)
2817 init_combo_box(builder, combo_name_map[ii].name);
2821 static const char * turbo_opts =
2822 "ref=1:subme=2:me=dia:analyse=none:trellis=0:"
2823 "no-fast-pskip=0:8x8dct=0";
2825 // Construct the x264 options string
2826 // The result is allocated, so someone must free it at some point.
2828 ghb_build_x264opts_string(GValue *settings)
2831 gchar *opts = ghb_settings_get_string(settings, "x264Option");
2838 result = g_strdup("");
2844 ghb_part_duration(gint tt, gint sc, gint ec, gint *hh, gint *mm, gint *ss)
2848 hb_chapter_t * chapter;
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;
2859 *mm = title->minutes;
2860 *ss = title->seconds;
2862 count = hb_list_count(title->list_chapter);
2863 if (sc > count) sc = count;
2864 if (ec > count) ec = count;
2866 if (sc == 1 && ec == count)
2870 for (c = sc; c <= ec; c++)
2872 chapter = hb_list_item(title->list_chapter, c-1);
2873 duration += chapter->duration;
2876 *hh = duration / 90000 / 3600;
2877 *mm = ((duration / 90000) % 3600) / 60;
2878 *ss = (duration / 90000) % 60;
2882 ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss)
2886 hb_chapter_t * chapter;
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;
2905 ghb_get_chapters(gint titleindex)
2909 hb_chapter_t * chapter;
2911 GValue *chapters = NULL;
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++)
2922 chapter = hb_list_item(title->list_chapter, ii);
2923 if (chapter == NULL) break;
2924 if (chapter->title == NULL || chapter->title[0] == 0)
2927 str = g_strdup_printf ("Chapter %2d", ii+1);
2928 ghb_array_append(chapters, ghb_string_value_new(str));
2933 ghb_array_append(chapters, ghb_string_value_new(chapter->title));
2940 ghb_ac3_in_audio_list(const GValue *audio_list)
2944 count = ghb_array_len(audio_list);
2945 for (ii = 0; ii < count; ii++)
2950 asettings = ghb_array_get_nth(audio_list, ii);
2951 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
2952 if (acodec & HB_ACODEC_AC3)
2959 audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
2962 GtkListStore *store;
2965 g_debug("audio_bitrate_opts_add ()\n");
2967 if (rate < 8) return;
2969 if (ghb_audio_bitrates[hb_audio_bitrates_count].string)
2971 g_free(ghb_audio_bitrates[hb_audio_bitrates_count].string);
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;
2978 store = get_combo_box_store(builder, name);
2979 if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
2981 str = g_strdup_printf ("<small>%d</small>", rate);
2982 gtk_list_store_append(store, &iter);
2983 gtk_list_store_set(store, &iter,
2986 2, ghb_audio_bitrates[hb_audio_bitrates_count].string,
2988 4, ghb_audio_bitrates[hb_audio_bitrates_count].string,
2995 audio_bitrate_opts_clean(
2996 GtkBuilder *builder,
3002 GtkListStore *store;
3004 gboolean done = FALSE;
3006 guint last = (guint)last_rate;
3007 guint first = (guint)first_rate;
3009 ghb_audio_bitrates_count = hb_audio_bitrates_count;
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))
3017 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
3019 ghb_audio_bitrates, ivalue, ghb_audio_bitrates_count) < 0)
3021 done = !gtk_list_store_remove(store, &iter);
3023 else if (ivalue < first || ivalue > last)
3026 gtk_list_store_set(store, &iter, 1, FALSE, -1);
3027 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
3032 gtk_list_store_set(store, &iter, 1, TRUE, -1);
3033 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
3040 audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
3043 GtkListStore *store;
3047 ghb_audio_bitrates_count = hb_audio_bitrates_count;
3048 ghb_audio_bitrates = calloc(hb_audio_bitrates_count+1, sizeof(hb_rate_t));
3050 for (ii = 0; ii < hb_audio_bitrates_count; ii++)
3052 ghb_audio_bitrates[ii] = hb_audio_bitrates[ii];
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++)
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,
3066 2, ghb_audio_bitrates[ii].string,
3067 3, (gdouble)ghb_audio_bitrates[ii].rate,
3068 4, ghb_audio_bitrates[ii].string,
3075 ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate)
3077 audio_bitrate_opts_add(builder, "AudioBitrate", bitrate);
3081 ghb_set_default_bitrate_opts(
3082 GtkBuilder *builder,
3086 audio_bitrate_opts_clean(builder, "AudioBitrate", first_rate, last_rate);
3089 static ghb_status_t hb_status;
3092 ghb_combo_init(signal_user_data_t *ud)
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);
3101 ghb_backend_init(gint debug)
3104 h_scan = hb_init( debug, 0 );
3105 h_queue = hb_init( debug, 0 );
3116 void ghb_backend_scan_stop()
3118 hb_scan_stop( h_scan );
3122 ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count, uint64_t min_duration)
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;
3133 ghb_backend_queue_scan(const gchar *path, gint titlenum)
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;
3141 ghb_get_scan_state()
3143 return hb_status.scan.state;
3147 ghb_get_queue_state()
3149 return hb_status.queue.state;
3153 ghb_clear_scan_state(gint state)
3155 hb_status.scan.state &= ~state;
3159 ghb_clear_queue_state(gint state)
3161 hb_status.queue.state &= ~state;
3165 ghb_set_scan_state(gint state)
3167 hb_status.scan.state |= state;
3171 ghb_set_queue_state(gint state)
3173 hb_status.queue.state |= state;
3177 ghb_get_status(ghb_status_t *status)
3179 memcpy(status, &hb_status, sizeof(ghb_status_t));
3188 if (h_scan == NULL) return;
3189 hb_get_state( h_scan, &s_scan );
3190 switch( s_scan.state )
3192 #define p s_scan.param.scanning
3193 case HB_STATE_SCANNING:
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;
3201 case HB_STATE_SCANDONE:
3203 hb_status.scan.state &= ~GHB_STATE_SCANNING;
3204 hb_status.scan.state |= GHB_STATE_SCANDONE;
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;
3223 case HB_STATE_PAUSED:
3224 hb_status.scan.state |= GHB_STATE_PAUSED;
3227 case HB_STATE_MUXING:
3229 hb_status.scan.state |= GHB_STATE_MUXING;
3232 #define p s_scan.param.workdone
3233 case HB_STATE_WORKDONE:
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;
3244 hb_status.scan.error = GHB_ERROR_NONE;
3246 case HB_ERROR_CANCELED:
3247 hb_status.scan.error = GHB_ERROR_CANCELED;
3250 hb_status.scan.error = GHB_ERROR_FAIL;
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 );
3263 hb_get_state( h_queue, &s_queue );
3264 switch( s_queue.state )
3266 #define p s_queue.param.scanning
3267 case HB_STATE_SCANNING:
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;
3275 case HB_STATE_SCANDONE:
3277 hb_status.queue.state &= ~GHB_STATE_SCANNING;
3278 hb_status.queue.state |= GHB_STATE_SCANDONE;
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;
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;
3313 case HB_STATE_PAUSED:
3314 hb_status.queue.state |= GHB_STATE_PAUSED;
3317 case HB_STATE_MUXING:
3319 hb_status.queue.state |= GHB_STATE_MUXING;
3322 #define p s_queue.param.workdone
3323 case HB_STATE_WORKDONE:
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;
3335 hb_status.queue.error = GHB_ERROR_NONE;
3337 case HB_ERROR_CANCELED:
3338 hb_status.queue.error = GHB_ERROR_CANCELED;
3341 hb_status.queue.error = GHB_ERROR_FAIL;
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 );
3357 ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
3362 if (h_scan == NULL) return FALSE;
3363 list = hb_get_titles( h_scan );
3364 if( !hb_list_count( list ) )
3366 /* No valid title, stop right there */
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;
3393 tinfo->angle_count = title->angle_count;
3394 tinfo->path = title->path;
3395 tinfo->name = title->name;
3396 tinfo->type = title->type;
3401 ghb_get_scan_audio_info(gint titleindex, gint audioindex)
3403 hb_audio_config_t *aconfig;
3405 aconfig = get_hb_audio(h_scan, titleindex, audioindex);
3410 ghb_audio_is_passthru(gint acodec)
3412 g_debug("ghb_audio_is_passthru () \n");
3413 return (acodec & HB_ACODEC_PASS_FLAG) != 0;
3417 ghb_audio_can_passthru(gint acodec)
3419 g_debug("ghb_audio_can_passthru () \n");
3420 return (acodec & HB_ACODEC_PASS_MASK) != 0;
3424 ghb_get_default_acodec()
3426 return HB_ACODEC_FAAC;
3430 picture_settings_deps(signal_user_data_t *ud)
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;
3438 pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
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));
3445 enable_keep_aspect = (pic_par != 1 && pic_par != 2);
3446 if (!enable_keep_aspect)
3448 ghb_ui_update(ud, "PictureKeepRatio", ghb_boolean_value(TRUE));
3450 keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
3451 autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
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;
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);
3482 ghb_set_scale(signal_user_data_t *ud, gint mode)
3487 gboolean keep_aspect;
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);
3499 gint max_height = 0;
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 ) )
3507 /* No valid title, stop right there */
3512 titleindex = ghb_settings_combo_int(ud->settings, "title");
3513 title = hb_list_item( list, titleindex );
3514 if (title == NULL) return;
3516 if (job == NULL) return;
3518 if (ud->scale_busy) return;
3519 ud->scale_busy = TRUE;
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
3536 keep_height = FALSE;
3538 // Step needs to be at least 2 because odd widths cause scaler crash
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);
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);
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);
3566 ghb_title_info_t tinfo;
3567 ghb_get_title_info (&tinfo, titleindex);
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]));
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");
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);
3596 need1 = (crop_height - height) / 2;
3597 need2 = crop_height - height - need1;
3600 need1 = (crop_width - width) / 2;
3601 need2 = crop_width - width - need1;
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]));
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];
3617 height = crop_height;
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)
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);
3631 g_debug("max_width %d, max_height %d\n", max_width, max_height);
3634 width = title->width - crop[2] - crop[3];
3636 height = title->height - crop[0] - crop[1];
3638 width = MOD_ROUND(width, mod);
3639 height = MOD_ROUND(height, mod);
3641 job->anamorphic.mode = pic_par;
3644 // The scaler crashes if the dimensions are not divisible by 2
3645 // Align mod 2. And so does something in x264_encoder_headers()
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;
3652 if (keep_height && pic_par == 2)
3653 width = ((double)height * crop_width / crop_height);
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)
3662 job->anamorphic.keep_display_aspect = 0;
3663 if (mode & GHB_PIC_KEEP_PAR)
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");
3672 job->anamorphic.dar_width =
3673 ghb_settings_get_int(ud->settings,
3674 "PictureDisplayWidth");
3675 job->anamorphic.dar_height = height;
3680 job->anamorphic.keep_display_aspect = 1;
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)
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,
3695 par_height = ghb_settings_get_int(ud->settings,
3696 "PicturePARHeight");
3701 // Adjust dims according to max values
3703 height = MIN(height, max_height);
3705 width = MIN(width, max_width);
3710 gint new_width, new_height;
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);
3719 if (max_width && new_width > max_width)
3721 height = new_height;
3723 else if (max_height && new_height > max_height)
3727 else if (keep_width)
3729 height = new_height;
3731 else if (keep_height)
3735 else if (width > new_width)
3737 height = new_height;
3743 g_debug("new w %d h %d\n", width, height);
3745 width = MOD_ROUND(width, mod);
3746 height = MOD_ROUND(height, mod);
3748 height = MIN(height, max_height);
3750 width = MIN(width, max_width);
3751 par_width = par_height = 1;
3753 ghb_ui_update(ud, "scale_width", ghb_int64_value(width));
3754 ghb_ui_update(ud, "scale_height", ghb_int64_value(height));
3756 gint disp_width, dar_width, dar_height;
3759 disp_width = (gdouble)(width * par_width / par_height) + 0.5;
3760 hb_reduce(&dar_width, &dar_height, disp_width, height);
3762 gint iaspect = dar_width * 9 / dar_height;
3763 if (dar_width > 2 * dar_height)
3765 str = g_strdup_printf("%.2f : 1", (gdouble)dar_width / dar_height);
3767 else if (iaspect <= 16 && iaspect >= 15)
3769 str = g_strdup_printf("%.2f : 9", (gdouble)dar_width * 9 / dar_height);
3771 else if (iaspect <= 12 && iaspect >= 11)
3773 str = g_strdup_printf("%.2f : 3", (gdouble)dar_width * 3 / dar_height);
3777 str = g_strdup_printf("%d : %d", dar_width, dar_height);
3779 ghb_ui_update(ud, "display_aspect", ghb_string_value(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;
3789 set_preview_job_settings(hb_job_t *job, GValue *settings)
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");
3796 job->anamorphic.mode = ghb_settings_combo_int(settings, "PicturePAR");
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"))
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]);
3808 job->width += xscale * (job->crop[2] + job->crop[3]);
3809 job->height += yscale * (job->crop[0] + job->crop[1]);
3817 gboolean decomb_deint = ghb_settings_get_boolean(settings, "PictureDecombDeinterlace");
3820 gint decomb = ghb_settings_combo_int(settings, "PictureDecomb");
3821 job->deinterlace = (decomb == 0) ? 0 : 1;
3825 gint deint = ghb_settings_combo_int(settings, "PictureDeinterlace");
3826 job->deinterlace = (deint == 0) ? 0 : 1;
3829 gboolean keep_aspect;
3830 keep_aspect = ghb_settings_get_boolean(settings, "PictureKeepRatio");
3831 if (job->anamorphic.mode)
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;
3838 if (job->anamorphic.mode == 3 && !keep_aspect)
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");
3848 job->anamorphic.keep_display_aspect = 1;
3854 ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
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;
3866 if (job == NULL) return 1500;
3867 size = ghb_settings_get_int(settings, "VideoTargetSize");
3868 return hb_calc_bitrate( job, size );
3872 ghb_validate_filter_string(const gchar *str, gint max_fields)
3878 if (str == NULL || *str == 0) return TRUE;
3881 val = g_strtod(str, &end);
3883 { // Found a numeric value
3885 // negative max_fields means infinate
3886 if (max_fields >= 0 && fields > max_fields) return FALSE;
3900 ghb_validate_filters(signal_user_data_t *ud)
3906 gboolean decomb_deint = ghb_settings_get_boolean(ud->settings, "PictureDecombDeinterlace");
3908 index = ghb_settings_combo_int(ud->settings, "PictureDeinterlace");
3909 if (!decomb_deint && index == 1)
3911 str = ghb_settings_get_string(ud->settings, "PictureDeinterlaceCustom");
3912 if (!ghb_validate_filter_string(str, -1))
3914 message = g_strdup_printf(
3915 "Invalid Deinterlace Settings:\n\n%s\n",
3917 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3925 index = ghb_settings_combo_int(ud->settings, "PictureDetelecine");
3928 str = ghb_settings_get_string(ud->settings, "PictureDetelecineCustom");
3929 if (!ghb_validate_filter_string(str, -1))
3931 message = g_strdup_printf(
3932 "Invalid Detelecine Settings:\n\n%s\n",
3934 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3942 index = ghb_settings_combo_int(ud->settings, "PictureDecomb");
3943 if (decomb_deint && index == 1)
3945 str = ghb_settings_get_string(ud->settings, "PictureDecombCustom");
3946 if (!ghb_validate_filter_string(str, -1))
3948 message = g_strdup_printf(
3949 "Invalid Decomb Settings:\n\n%s\n",
3951 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3959 index = ghb_settings_combo_int(ud->settings, "PictureDenoise");
3962 str = ghb_settings_get_string(ud->settings, "PictureDenoiseCustom");
3963 if (!ghb_validate_filter_string(str, -1))
3965 message = g_strdup_printf(
3966 "Invalid Denoise Settings:\n\n%s\n",
3968 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3979 ghb_validate_video(signal_user_data_t *ud)
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))
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"))
3999 vcodec = HB_VCODEC_FFMPEG;
4000 ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
4006 ghb_validate_subtitles(signal_user_data_t *ud)
4012 if (h_scan == NULL) return FALSE;
4013 list = hb_get_titles( h_scan );
4014 if( !hb_list_count( list ) )
4016 /* No valid title, stop right there */
4017 g_message("No title found.\n");
4023 titleindex = ghb_settings_combo_int(ud->settings, "title");
4024 title = hb_list_item( list, titleindex );
4025 if (title == NULL) return FALSE;
4027 const GValue *slist, *settings;
4028 gint count, ii, source;
4029 gboolean burned, one_burned = FALSE;
4031 slist = ghb_settings_get_value(ud->settings, "subtitle_list");
4032 count = ghb_array_len(slist);
4033 for (ii = 0; ii < count; ii++)
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)
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"))
4058 if (source == SRTSUB)
4062 filename = ghb_settings_get_string(settings, "SrtFile");
4063 if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
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"))
4084 ghb_select_audio_codec(GValue *settings, hb_audio_config_t *aconfig, gint acodec)
4086 gint mux = ghb_settings_combo_int(settings, "FileFormat");
4088 guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK;
4089 if (mux == HB_MUX_MP4)
4091 if ((acodec & in_codec & HB_ACODEC_AC3))
4093 return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4095 else if (acodec & HB_ACODEC_AC3)
4097 return HB_ACODEC_AC3;
4099 else if (acodec & HB_ACODEC_LAME)
4101 return HB_ACODEC_LAME;
4103 else if (acodec & HB_ACODEC_FAAC)
4105 return HB_ACODEC_FAAC;
4109 return HB_ACODEC_FAAC;
4114 if ((acodec & in_codec & HB_ACODEC_PASS_MASK))
4116 return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
4118 else if (acodec & HB_ACODEC_AC3)
4120 return HB_ACODEC_AC3;
4122 else if (acodec & HB_ACODEC_VORBIS)
4124 return HB_ACODEC_VORBIS;
4126 else if (acodec & HB_ACODEC_LAME)
4128 return HB_ACODEC_LAME;
4130 else if (acodec & HB_ACODEC_FAAC)
4132 return HB_ACODEC_FAAC;
4136 return HB_ACODEC_LAME;
4142 ghb_validate_audio(signal_user_data_t *ud)
4149 if (h_scan == NULL) return FALSE;
4150 list = hb_get_titles( h_scan );
4151 if( !hb_list_count( list ) )
4153 /* No valid title, stop right there */
4154 g_message("No title found.\n");
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");
4165 const GValue *audio_list;
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++)
4173 hb_audio_config_t *aconfig;
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)
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)))
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"))
4198 if ((codec & HB_ACODEC_AC3) ||
4199 aconfig->in.codec == HB_ACODEC_DCA)
4201 codec = HB_ACODEC_AC3;
4203 else if (mux == HB_MUX_MKV)
4205 codec = HB_ACODEC_LAME;
4209 codec = HB_ACODEC_FAAC;
4211 value = ghb_lookup_acodec_value(codec);
4212 ghb_settings_take_value(asettings, "AudioEncoder", value);
4214 gchar *a_unsup = NULL;
4215 gchar *mux_s = NULL;
4216 if (mux == HB_MUX_MP4)
4219 // mp4/vorbis|DTS combination is not supported.
4220 if (codec == HB_ACODEC_VORBIS)
4223 codec = HB_ACODEC_FAAC;
4225 if (codec == HB_ACODEC_DCA)
4228 codec = HB_ACODEC_AC3;
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"))
4243 value = ghb_lookup_acodec_value(codec);
4244 ghb_settings_take_value(asettings, "AudioEncoder", value);
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;
4255 gint best = hb_get_best_mixdown(codec, aconfig->in.channel_layout, 0);
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;
4262 gchar *mix_unsup = NULL;
4263 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
4267 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
4269 mix_unsup = "stereo";
4271 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
4273 mix_unsup = "Dolby";
4275 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
4277 mix_unsup = "Dolby Pro Logic II";
4279 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
4281 mix_unsup = "6 Channel";
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"))
4295 mix = ghb_get_best_mix(aconfig, codec, mix);
4296 value = get_amix_value(mix);
4297 ghb_settings_take_value(asettings, "AudioMixdown", value);
4304 ghb_validate_vquality(GValue *settings)
4310 if (ghb_settings_get_boolean(settings, "nocheckvquality")) return TRUE;
4311 vcodec = ghb_settings_combo_int(settings, "VideoEncoder");
4313 vquality = ghb_settings_get_double(settings, "VideoQualitySlider");
4314 if (ghb_settings_get_boolean(settings, "vquality_type_constant"))
4318 case HB_VCODEC_X264:
4324 case HB_VCODEC_FFMPEG:
4330 case HB_VCODEC_THEORA:
4342 if (vcodec == HB_VCODEC_X264 && vquality == 0.0)
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"))
4359 else if (vquality < min || vquality > max)
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"))
4379 add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
4384 static gchar *x264opts;
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;
4394 g_debug("add_job()\n");
4395 if (h == NULL) return;
4396 list = hb_get_titles( h );
4397 if( !hb_list_count( list ) )
4399 /* No valid title, stop right there */
4403 title = hb_list_item( list, titleindex );
4404 if (title == NULL) return;
4406 /* Set job settings */
4408 if (job == NULL) return;
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)
4414 job->seek_points = ghb_settings_get_int(js, "preview_count");
4415 job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL;
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)
4422 job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile");
4423 job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize");
4427 job->largeFileSize = FALSE;
4428 job->mp4_optimize = FALSE;
4430 if (!job->start_at_preview)
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;
4438 if (ghb_settings_combo_int(js, "PtoPType") == 0)
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 );
4446 if (ghb_settings_combo_int(js, "PtoPType") == 1)
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 -
4456 if (ghb_settings_combo_int(js, "PtoPType") == 2)
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");
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;
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 )
4478 chapters = ghb_settings_get_value(js, "chapter_list");
4479 count = ghb_array_len(chapters);
4480 for(chap = 0; chap < count; chap++)
4482 hb_chapter_t * chapter_s;
4486 chapter = ghb_array_get_nth(chapters, chap);
4487 name = ghb_value_string(chapter);
4490 name = g_strdup_printf ("Chapter %2d", chap+1);
4492 chapter_s = hb_list_item( job->title->list_chapter, chap);
4493 strncpy(chapter_s->title, name, 1023);
4494 chapter_s->title[1023] = '\0';
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");
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");
4509 job->deinterlace = (deint != 0) ? 1 : 0;
4511 job->deinterlace = 0;
4512 job->grayscale = ghb_settings_get_boolean(js, "VideoGrayScale");
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)
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;
4525 if (job->anamorphic.mode == 3 && !keep_aspect)
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");
4535 job->anamorphic.keep_display_aspect = 1;
4539 /* Add selected filters */
4540 job->filters = hb_list_init();
4541 gint detel = ghb_settings_combo_int(js, "PictureDetelecine");
4546 if (detel_opts.map[detel].svalue != NULL)
4547 detel_str = g_strdup(detel_opts.map[detel].svalue);
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 );
4554 if ( decomb_deint && decomb )
4558 if (decomb_opts.map[decomb].svalue != NULL)
4559 decomb_str = g_strdup(decomb_opts.map[decomb].svalue);
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 );
4566 if( job->deinterlace )
4570 if (deint_opts.map[deint].svalue != NULL)
4571 deint_str = g_strdup(deint_opts.map[deint].svalue);
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 );
4578 gint deblock = ghb_settings_get_int(js, "PictureDeblock");
4581 deblock_str = g_strdup_printf("%d", deblock);
4582 hb_filter_deblock.settings = deblock_str;
4583 hb_list_add( job->filters, &hb_filter_deblock );
4585 gint denoise = ghb_settings_combo_int(js, "PictureDenoise");
4590 if (denoise_opts.map[denoise].svalue != NULL)
4591 denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
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 );
4598 job->width = ghb_settings_get_int(js, "scale_width");
4599 job->height = ghb_settings_get_int(js, "scale_height");
4601 job->vcodec = ghb_settings_combo_int(js, "VideoEncoder");
4602 if ((job->mux == HB_MUX_MP4 ) && (job->vcodec == HB_VCODEC_THEORA))
4604 // mp4/theora combination is not supported.
4605 job->vcodec = HB_VCODEC_FFMPEG;
4607 if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
4609 job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible");
4611 if (ghb_settings_get_boolean(js, "vquality_type_constant"))
4614 vquality = ghb_settings_get_double(js, "VideoQualitySlider");
4615 job->vquality = vquality;
4618 else if (ghb_settings_get_boolean(js, "vquality_type_bitrate"))
4620 job->vquality = -1.0;
4621 job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
4624 gint vrate = ghb_settings_combo_int(js, "VideoFramerate");
4627 job->vrate = title->rate;
4628 job->vrate_base = title->rate_base;
4633 job->vrate = 27000000;
4634 job->vrate_base = vrate;
4635 gboolean pfr = ghb_settings_get_boolean(js, "VideoFrameratePFR");
4642 const GValue *audio_list;
4646 audio_list = ghb_settings_get_value(js, "audio_list");
4647 count = ghb_array_len(audio_list);
4648 for (ii = 0; ii < count; ii++)
4651 hb_audio_config_t audio;
4652 hb_audio_config_t *aconfig;
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;
4660 aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
4661 title->list_audio, audio.in.track );
4663 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
4664 audio.out.codec = ghb_select_audio_codec(js, aconfig, acodec);
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;
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))
4674 audio.out.mixdown = 0;
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,
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;
4688 audio.out.samplerate = srate;
4690 audio.out.bitrate = hb_get_best_audio_bitrate(
4691 audio.out.codec, audio.out.bitrate,
4692 audio.out.samplerate, audio.out.mixdown);
4695 // Add it to the jobs audio list
4696 hb_audio_add( job, &audio );
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"))
4706 size = ghb_settings_get_int(js, "VideoTargetSize");
4707 job->vbitrate = hb_calc_bitrate( job, size );
4708 job->vquality = -1.0;
4711 dest_str = ghb_settings_get_string(js, "destination");
4712 job->file = dest_str;
4714 const GValue *subtitle_list;
4716 gboolean force, burned, def, one_burned = FALSE;
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++)
4726 ssettings = ghb_array_get_nth(subtitle_list, ii);
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");
4733 if (source == SRTSUB)
4735 hb_subtitle_config_t sub_config;
4736 gchar *filename, *lang, *code;
4738 filename = ghb_settings_get_string(ssettings, "SrtFile");
4739 if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
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;
4754 hb_srt_add( job, &sub_config, lang);
4762 subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack");
4767 job->select_subtitle_config.dest = PASSTHRUSUB;
4771 // Only allow one subtitle to be burned into the video
4774 job->select_subtitle_config.dest = RENDERSUB;
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);
4782 else if (subtitle >= 0)
4784 hb_subtitle_t * subt;
4785 hb_subtitle_config_t sub_config;
4787 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
4790 sub_config = subt->config;
4793 sub_config.dest = PASSTHRUSUB;
4795 else if ( burned && canBurn(subt->source) )
4797 // Only allow one subtitle to be burned into the video
4800 sub_config.dest = RENDERSUB;
4803 sub_config.force = force;
4804 sub_config.default_track = def;
4805 hb_subtitle_add( job, &sub_config, subtitle );
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);
4817 if( *x264opts == '\0' )
4823 if (job->indepth_scan == 1)
4825 // Subtitle scan. Look for subtitle matching audio language
4828 * When subtitle scan is enabled do a fast pre-scan job
4829 * which will determine which subtitles to enable, if any.
4832 job->indepth_scan = 1;
4833 job->x264opts = NULL;
4836 * Add the pre-scan job
4838 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4842 if( ghb_settings_get_boolean(js, "VideoTwoPass") &&
4843 !ghb_settings_get_boolean(js, "vquality_type_constant"))
4846 * If subtitle_scan is enabled then only turn it on
4847 * for the second pass and then off again for the
4851 job->indepth_scan = 0;
4854 * If turbo options have been selected then append them
4855 * to the x264opts now (size includes one ':' and the '\0')
4857 if( ghb_settings_get_boolean(js, "VideoTurboTwoPass") )
4859 gchar *tmp_x264opts;
4863 badapt = ghb_lookup_badapt(x264opts);
4866 extra_opts = g_strdup_printf("%s", turbo_opts);
4870 extra_opts = g_strdup_printf("%s:weightb=0", turbo_opts);
4875 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, extra_opts);
4880 * No x264opts to modify, but apply the turbo options
4881 * anyway as they may be modifying defaults
4883 tmp_x264opts = g_strdup_printf("%s", extra_opts);
4887 job->x264opts = tmp_x264opts;
4891 job->x264opts = x264opts;
4893 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4895 //if (job->x264opts != NULL)
4896 // g_free(job->x264opts);
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).
4905 job->indepth_scan = 0;
4906 job->x264opts = x264opts;
4907 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4909 //if (job->x264opts != NULL)
4910 // g_free(job->x264opts);
4914 job->x264opts = x264opts;
4915 job->indepth_scan = 0;
4917 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
4919 //if (job->x264opts != NULL)
4920 // g_free(job->x264opts);
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++)
4927 hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
4928 hb_list_rem(job->list_audio, audio);
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++)
4936 hb_subtitle_t *subtitle = hb_list_item(job->list_subtitle, 0);
4937 hb_list_rem(job->list_subtitle, subtitle);
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);
4950 ghb_add_job(GValue *js, gint unique_id)
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);
4958 ghb_add_live_job(GValue *js, gint unique_id)
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);
4967 ghb_remove_job(gint unique_id)
4972 // Multiples passes all get the same id
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)
4978 if ((job->sequence_id & 0xFFFFFF) == unique_id)
4979 hb_rem(h_queue, job);
4986 hb_start( h_queue );
4996 ghb_start_live_encode()
5002 ghb_stop_live_encode()
5011 hb_get_state2( h_queue, &s );
5013 if( s.state == HB_STATE_PAUSED )
5015 hb_status.queue.state &= ~GHB_STATE_PAUSED;
5016 hb_resume( h_queue );
5020 hb_status.queue.state |= GHB_STATE_PAUSED;
5021 hb_pause( h_queue );
5036 guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5039 gint channels = gdk_pixbuf_get_n_channels (pb);
5040 gint stride = gdk_pixbuf_get_rowstride (pb);
5042 for (jj = 0; jj < width; jj++)
5044 dst = pixels + y * stride + (x+jj) * channels;
5045 for (ii = 0; ii < len; ii++)
5066 guint8 *pixels = gdk_pixbuf_get_pixels (pb);
5069 gint channels = gdk_pixbuf_get_n_channels (pb);
5070 gint stride = gdk_pixbuf_get_rowstride (pb);
5072 for (jj = 0; jj < width; jj++)
5074 dst = pixels + (y+jj) * stride + x * channels;
5075 for (ii = 0; ii < len; ii++)
5096 gint line_width = 8;
5103 {{0x80, 0x80, 0x80},{0xC0, 0x80, 0x70},{0x80, 0xA0, 0x80},{0x70, 0x80, 0xA0}};
5108 for (ii = x, jj = 0; ii+line_width < x+w; ii += step, jj++)
5110 vert_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, ii, y, h, line_width);
5116 for (ii = y, jj = 0; ii+line_width < y+h; ii += step, jj++)
5118 horz_line(pb, c[jj&3].r, c[jj&3].g, c[jj&3].b, x, ii, w, line_width);
5124 ghb_get_preview_image(
5127 signal_user_data_t *ud,
5135 settings = ud->settings;
5136 list = hb_get_titles( h_scan );
5137 if( !hb_list_count( list ) )
5139 /* No valid title, stop right there */
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);
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");
5153 hb_set_anamorphic_size( title->job, &width, &height,
5154 &par_width, &par_height );
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;
5161 static guint8 *buffer = NULL;
5162 static gint bufferSize = 0;
5165 newSize = dstWidth * dstHeight * 4;
5166 if( bufferSize < newSize )
5168 bufferSize = newSize;
5169 buffer = (guint8*) g_realloc( buffer, bufferSize );
5171 hb_get_preview( h_scan, title, index, buffer );
5173 // Create an GdkPixbuf and copy the libhb image into it, converting it from
5174 // libhb's format something suitable.
5176 // The image data returned by hb_get_preview is 4 bytes per pixel,
5177 // BGRA format. Alpha is ignored.
5179 GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
5180 guint8 *pixels = gdk_pixbuf_get_pixels (preview);
5182 guint32 *src = (guint32*)buffer;
5183 guint8 *dst = pixels;
5186 gint channels = gdk_pixbuf_get_n_channels (preview);
5187 gint stride = gdk_pixbuf_get_rowstride (preview);
5190 for (ii = 0; ii < dstHeight; ii++)
5193 for (jj = 0; jj < dstWidth; jj++)
5195 tmp[0] = src[0] >> 16;
5196 tmp[1] = src[0] >> 8;
5197 tmp[2] = src[0] >> 0;
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);
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");
5213 gdouble xscale = (gdouble)w / (gdouble)(title->width - c2 - c3);
5214 gdouble yscale = (gdouble)h / (gdouble)(title->height - c0 - c1);
5216 ghb_par_scale(ud, &dstWidth, &dstHeight, par_width, par_height);
5219 if (ghb_settings_get_boolean(settings, "reduce_hd_preview"))
5223 gint orig_w, orig_h;
5226 if (ghb_settings_get_boolean(settings, "preview_fullscreen"))
5230 ss = gdk_screen_get_default();
5231 s_w = gdk_screen_get_width(ss);
5232 s_h = gdk_screen_get_height(ss);
5236 if (dstWidth > s_w * factor / 100)
5238 dstWidth = s_w * factor / 100;
5239 dstHeight = dstHeight * dstWidth / orig_w;
5241 if (dstHeight > s_h * factor / 100)
5243 dstHeight = s_h * factor / 100;
5244 dstWidth = dstWidth * dstHeight / orig_h;
5246 xscale *= (gdouble)dstWidth / orig_w;
5247 yscale *= (gdouble)dstHeight / orig_h;
5248 w *= (gdouble)dstWidth / orig_w;
5249 h *= (gdouble)dstHeight / orig_h;
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"))
5260 hash_pixbuf(scaled_preview, c2, 0, w, c0, 32, 0);
5262 hash_pixbuf(scaled_preview, c2, dstHeight-c1, w, c1, 32, 0);
5264 hash_pixbuf(scaled_preview, 0, c0, c2, h, 32, 1);
5266 hash_pixbuf(scaled_preview, dstWidth-c3, c0, c3, h, 32, 1);
5268 g_object_unref (preview);
5269 return scaled_preview;
5273 sanitize_volname(gchar *name)
5298 ghb_dvd_volname(const gchar *device)
5301 name = hb_dvd_name((gchar*)device);
5302 if (name != NULL && name[0] != 0)
5304 name = g_strdup(name);
5305 sanitize_volname(name);