diff options
-rw-r--r-- | contrib/libmkv/module.defs | 3 | ||||
-rw-r--r-- | gtk/src/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/src/callbacks.c | 10 | ||||
-rw-r--r-- | gtk/src/ghb.ui | 178 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 472 | ||||
-rw-r--r-- | gtk/src/hb-backend.h | 19 | ||||
-rw-r--r-- | gtk/src/internal_defaults.xml | 18 | ||||
-rw-r--r-- | gtk/src/main.c | 64 | ||||
-rw-r--r-- | gtk/src/presets.c | 139 | ||||
-rw-r--r-- | gtk/src/queuehandler.c | 4 | ||||
-rw-r--r-- | gtk/src/settings.c | 6 | ||||
-rw-r--r-- | gtk/src/settings.h | 1 | ||||
-rw-r--r-- | libhb/common.h | 5 | ||||
-rw-r--r-- | libhb/decvobsub.c | 102 | ||||
-rw-r--r-- | libhb/dvdnav.c | 4 | ||||
-rw-r--r-- | libhb/encvobsub.c | 18 | ||||
-rw-r--r-- | libhb/fifo.c | 1 | ||||
-rw-r--r-- | libhb/muxmkv.c | 87 | ||||
-rw-r--r-- | libhb/reader.c | 2 | ||||
-rw-r--r-- | libhb/sync.c | 246 | ||||
-rw-r--r-- | libhb/work.c | 8 | ||||
-rw-r--r-- | macosx/Controller.mm | 8 | ||||
-rw-r--r-- | test/test.c | 8 |
23 files changed, 1008 insertions, 397 deletions
diff --git a/contrib/libmkv/module.defs b/contrib/libmkv/module.defs index 102aea033..3805d25a4 100644 --- a/contrib/libmkv/module.defs +++ b/contrib/libmkv/module.defs @@ -1,5 +1,4 @@ $(eval $(call import.MODULE.defs,LIBMKV,libmkv)) $(eval $(call import.CONTRIB.defs,LIBMKV)) -LIBMKV.FETCH.url = http://download.m0k.org/handbrake/contrib/libmkv-0.6.3.1.tar.gz -LIBMKV.EXTRACT.tarbase = libmkv +LIBMKV.FETCH.url = http://download.m0k.org/handbrake/contrib/libmkv-0.6.4.tar.bz2 diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am index 71b3ac363..b435cd1c2 100644 --- a/gtk/src/Makefile.am +++ b/gtk/src/Makefile.am @@ -68,6 +68,8 @@ ghb_SOURCES = \ queuehandler.h \ audiohandler.c \ audiohandler.h \ + subtitlehandler.c \ + subtitlehandler.h \ x264handler.c \ x264handler.h \ main.c \ diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index f2d964290..e2140d7d5 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -44,6 +44,7 @@ #include "callbacks.h" #include "queuehandler.h" #include "audiohandler.h" +#include "subtitlehandler.h" #include "resources.h" #include "settings.h" #include "presets.h" @@ -1118,6 +1119,7 @@ container_changed_cb(GtkWidget *widget, signal_user_data_t *ud) } g_free(container); } + ghb_subtitle_adjust_burn(ud); } static gchar* @@ -1254,10 +1256,10 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_check_dependency(ud, widget); titleindex = ghb_settings_combo_int(ud->settings, "title"); - ghb_update_ui_combo_box (ud->builder, "AudioTrack", titleindex, FALSE); - ghb_update_ui_combo_box (ud->builder, "Subtitles", titleindex, FALSE); + ghb_update_ui_combo_box (ud, "AudioTrack", titleindex, FALSE); + ghb_update_ui_combo_box (ud, "SubtitleTrack", titleindex, FALSE); - ghb_update_from_preset(ud, "Subtitles"); + ghb_set_pref_subtitle(titleindex, ud); if (ghb_get_title_info (&tinfo, titleindex)) { show_title_info(ud, &tinfo); @@ -2019,7 +2021,7 @@ ghb_backend_events(signal_user_data_t *ud) ghb_title_info_t tinfo; - ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE); + ghb_update_ui_combo_box(ud, "title", 0, FALSE); titleindex = ghb_longest_title(); ghb_ui_update(ud, "title", ghb_int64_value(titleindex)); diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui index 8d52e299b..57a941f7e 100644 --- a/gtk/src/ghb.ui +++ b/gtk/src/ghb.ui @@ -2153,7 +2153,7 @@ </object> </child> <child type="label"> - <object class="GtkLabel" id="label74"> + <object class="GtkLabel" id="label87"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="label" translatable="yes"><b>Preferred Audio Language</b></property> @@ -2162,80 +2162,164 @@ </child> </object> </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label48"> + <property name="visible">True</property> + <property name="label" translatable="yes">Audio</property> + </object> + <packing> + <property name="position">2</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="subtitle_tab"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <object class="GtkFrame" id="frame20"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> <child> - <object class="GtkFrame" id="frame19"> + <object class="GtkAlignment" id="alignment23"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> + <property name="top_padding">6</property> + <property name="bottom_padding">2</property> + <property name="left_padding">12</property> + <property name="right_padding">2</property> <child> - <object class="GtkAlignment" id="alignment58"> + <object class="GtkVBox" id="vbox12"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="top_padding">6</property> - <property name="bottom_padding">2</property> - <property name="left_padding">12</property> - <property name="right_padding">2</property> + <property name="spacing">2</property> <child> - <object class="GtkHBox" id="hbox65"> + <object class="GtkHBox" id="hbox45"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="spacing">5</property> - <child> - <object class="GtkComboBox" id="Subtitles"> - <property name="width_request">150</property> + <object class="GtkButton" id="subtitle_add"> <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal handler="subtitle_changed_cb" name="changed"/> + <property name="tooltip-text" translatable="yes">Add new audio settings to the list</property> + <property name="relief">GTK_RELIEF_NONE</property> + <signal handler="subtitle_add_clicked_cb" name="clicked"/> + <child> + <object class="GtkImage" id="image9"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="stock">gtk-add</property> + </object> + </child> </object> + <packing> + <property name="expand">False</property> + </packing> </child> <child> - <object class="GtkCheckButton" id="SubtitlesForced"> + <object class="GtkButton" id="subtitle_remove"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="has_tooltip">True</property> - <property name="tooltip-text" translatable="yes">These are subtitles that a regular DVD player would automatically show.</property> - <property name="label" translatable="yes">Allow only forced subtitles</property> - <property name="draw_indicator">True</property> - <signal handler="setting_widget_changed_cb" name="toggled"/> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="tooltip-text" translatable="yes">Remove the selected audio settings</property> + <property name="relief">GTK_RELIEF_NONE</property> + <signal handler="subtitle_remove_clicked_cb" name="clicked"/> + <child> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="stock">gtk-remove</property> + </object> + </child> </object> <packing> + <property name="expand">False</property> <property name="position">1</property> </packing> </child> + <child> + <object class="GtkAlignment" id="alignment44"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">1</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <child> + <object class="GtkHBox" id="hbox21"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">5</property> + <child> + <object class="GtkLabel" id="label24"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Subtitle:</property> + </object> + </child> + <child> + <object class="GtkComboBox" id="SubtitleTrack"> + <property name="width_request">150</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal handler="subtitle_track_changed_cb" name="changed"/> + </object> + <packing> + <property name="position">1</property> + <property name="expand">False</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> </object> + <packing> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkTreeView" id="subtitle_list"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="headers_clickable">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label75"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes"><b>Subtitles</b></property> - <property name="use_markup">True</property> </object> </child> </object> - <packing> - <property name="position">1</property> - </packing> </child> </object> - <packing> - <property name="expand">False</property> - <property name="position">3</property> - </packing> </child> </object> </child> <child type="tab"> - <object class="GtkLabel" id="label48"> + <object class="GtkLabel" id="label9"> <property name="visible">True</property> - <property name="label" translatable="yes">Audio/Subtitles</property> + <property name="label" translatable="yes">Subtitles</property> </object> <packing> - <property name="position">2</property> + <property name="position">3</property> <property name="tab_fill">False</property> </packing> </child> @@ -3053,7 +3137,7 @@ no-dct-decimate=0:cabac=1</property> <property name="label" translatable="yes">H.264</property> </object> <packing> - <property name="position">3</property> + <property name="position">4</property> <property name="tab_fill">False</property> </packing> </child> @@ -3118,7 +3202,7 @@ no-dct-decimate=0:cabac=1</property> <property name="label" translatable="yes">Chapters</property> </object> <packing> - <property name="position">4</property> + <property name="position">5</property> <property name="tab_fill">False</property> </packing> </child> @@ -4597,7 +4681,7 @@ the required multiple.</property> </object> </child> <child type="label"> - <object class="GtkLabel" id="label29"> + <object class="GtkLabel" id="label25"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="label" translatable="yes"><b>Storage</b></property> @@ -4862,7 +4946,7 @@ the required multiple.</property> </packing> </child> <child> - <object class="GtkAlignment" id="alignment2"> + <object class="GtkAlignment" id="alignment27"> <property name="visible">True</property> <property name="xalign">0</property> <property name="xscale">0</property> @@ -4875,7 +4959,7 @@ the required multiple.</property> <property name="column_spacing">5</property> <child> - <object class="GtkLabel" id="label56"> + <object class="GtkLabel" id="label41"> <property name="visible">True</property> <property name="xalign">0</property> <property name="label" translatable="yes">Deblock:</property> @@ -4974,7 +5058,7 @@ the required multiple.</property> <property name="column_spacing">5</property> <child> - <object class="GtkLabel" id="label56"> + <object class="GtkLabel" id="label86"> <property name="visible">True</property> <property name="xalign">0</property> <property name="label" translatable="yes">Detelecine:</property> @@ -5627,7 +5711,7 @@ libxvidcore authors: <property name="visible_window">False</property> <property name="above_child">True</property> <child> - <object class="GtkImage" id="image3"> + <object class="GtkImage" id="image10"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="icon_name">hb-icon</property> @@ -5685,7 +5769,7 @@ libxvidcore authors: <property name="label_xalign">0</property> <property name="shadow_type">etched-out</property> <child> - <object class="GtkAlignment" id="alignment2"> + <object class="GtkAlignment" id="alignment28"> <property name="visible">True</property> <property name="left_padding">12</property> <child> @@ -5793,7 +5877,7 @@ libxvidcore authors: </packing> </child> <child> - <object class="GtkAlignment" id="alignment1"> + <object class="GtkAlignment" id="alignment24"> <property name="visible">True</property> <property name="xalign">0</property> <property name="xscale">0</property> diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index 0b7633da6..bb30d2c28 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -30,6 +30,7 @@ #include "hb-backend.h" #include "settings.h" #include "callbacks.h" +#include "subtitlehandler.h" #include "preview.h" #include "values.h" #include "lang.h" @@ -48,20 +49,24 @@ typedef struct options_map_t *map; } combo_opts_t; -static const gchar *index_str[] = -{ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", -}; +static gchar **index_str = NULL; +static gint index_str_size = 0; + +static void +index_str_init(gint max_index) +{ + int ii; + + if (max_index+1 > index_str_size) + { + index_str = realloc(index_str, (max_index+1) * sizeof(char*)); + for (ii = index_str_size; ii <= max_index; ii++) + { + index_str[ii] = g_strdup_printf("%d", ii); + } + index_str_size = max_index + 1; + } +} static options_map_t d_par_opts[] = { @@ -330,7 +335,7 @@ combo_name_map_t combo_name_map[] = {"x264_subme", &subme_opts}, {"x264_analyse", &analyse_opts}, {"x264_trellis", &trellis_opts}, - {"Subtitles", &subtitle_opts}, + {"SubtitleTrack", &subtitle_opts}, {"title", &title_opts}, {"AudioTrack", &audio_track_opts}, {NULL, NULL} @@ -629,6 +634,26 @@ ghb_vquality_range( } } +static const gchar* +lookup_generic_string(combo_opts_t *opts, const GValue *gval) +{ + gint ii; + gchar *str; + const gchar *result = ""; + + str = ghb_value_string(gval); + for (ii = 0; ii < opts->count; ii++) + { + if (strcmp(opts->map[ii].shortOpt, str) == 0) + { + result = opts->map[ii].svalue; + break; + } + } + g_free(str); + return result; +} + static gint lookup_generic_int(combo_opts_t *opts, const GValue *gval) { @@ -964,6 +989,92 @@ ghb_hb_cleanup(gboolean partial) } gint +ghb_subtitle_track_source(signal_user_data_t *ud, gint track) +{ + gint titleindex; + + if (track == -2) + return CC608SUB; + if (track < 0) + return VOBSUB; + titleindex = ghb_settings_combo_int(ud->settings, "title"); + if (titleindex < 0) + return VOBSUB; + + hb_list_t * list; + hb_title_t * title; + hb_subtitle_t * sub; + + if (h_scan == NULL) return VOBSUB; + list = hb_get_titles( h_scan ); + if( !hb_list_count( list ) ) + { + /* No valid title, stop right there */ + return VOBSUB; + } + title = hb_list_item( list, titleindex ); + if (title == NULL) return VOBSUB; // Bad titleindex + sub = hb_list_item( title->list_subtitle, track); + if (sub != NULL) + return sub->source; + else + return VOBSUB; +} + +const char* +ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track) +{ + gint titleindex; + const gchar * name = "Unknown"; + + if (track == -2) + return CC608SUB; + if (track < 0) + return VOBSUB; + if (track < 0) + goto done; + + titleindex = ghb_settings_combo_int(ud->settings, "title"); + if (titleindex < 0) + goto done; + + hb_list_t * list; + hb_title_t * title; + hb_subtitle_t * sub; + + if (h_scan == NULL) return VOBSUB; + list = hb_get_titles( h_scan ); + if( !hb_list_count( list ) ) + goto done; + + title = hb_list_item( list, titleindex ); + if (title == NULL) + goto done; + + sub = hb_list_item( title->list_subtitle, track); + if (sub != NULL) + { + switch (sub->source) + { + case VOBSUB: + name = "Bitmap"; + break; + case CC708SUB: + case CC608SUB: + case SRTSUB: + name = "Text"; + break; + default: + break; + } + } + +done: + return name; +} + + +gint ghb_get_title_number(gint titleindex) { hb_list_t * list; @@ -1544,6 +1655,7 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) audio_track_opts.map[0].svalue = "none"; return; } + index_str_init(count-1); for (ii = 0; ii < count; ii++) { audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, ii ); @@ -1562,20 +1674,18 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) } } - void -subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) +subtitle_opts_set(signal_user_data_t *ud, const gchar *name, gint titleindex) { GtkTreeIter iter; GtkListStore *store; hb_list_t * list = NULL; hb_title_t * title = NULL; - hb_subtitle_t * subtitle; - gint ii; - gint count = 0; + hb_subtitle_t * subtitle; + gint ii, count = 0; g_debug("subtitle_opts_set () %s\n", name); - store = get_combo_box_store(builder, name); + store = get_combo_box_store(ud->builder, name); gtk_list_store_clear(store); if (h_scan != NULL) { @@ -1590,74 +1700,77 @@ subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) if (subtitle_opts.map) g_free(subtitle_opts.map); if (count > 0) { - subtitle_opts.count = count+2; - subtitle_opts.map = g_malloc((count+2)*sizeof(options_map_t)); + subtitle_opts.count = count+1; + subtitle_opts.map = g_malloc((count+1)*sizeof(options_map_t)); } else { subtitle_opts.count = LANG_TABLE_SIZE+2; subtitle_opts.map = g_malloc((LANG_TABLE_SIZE+2)*sizeof(options_map_t)); } - // Add options for "none" and "autoselect" - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, "None", - 1, TRUE, - 2, "none", - 3, -2.0, - 4, "none", - -1); - subtitle_opts.map[0].option = "None"; - subtitle_opts.map[0].shortOpt = "none"; - subtitle_opts.map[0].ivalue = -2; - subtitle_opts.map[0].svalue = "none"; gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, "Autoselect", 1, TRUE, - 2, "auto", + 2, "-1", 3, -1.0, 4, "auto", -1); - subtitle_opts.map[1].option = "Same as audio"; - subtitle_opts.map[1].shortOpt = "auto"; - subtitle_opts.map[1].ivalue = -1; - subtitle_opts.map[1].svalue = "auto"; + subtitle_opts.map[0].option = "Same as audio"; + subtitle_opts.map[0].shortOpt = "-1"; + subtitle_opts.map[0].ivalue = -1; + subtitle_opts.map[0].svalue = "auto"; if (count > 0) { + index_str_init(count-1); for (ii = 0; ii < count; ii++) { subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii); + // Skip subtitles that must be burned if there is already + // a burned subtitle in the list + subtitle_opts.map[ii+1].option = subtitle->lang; + subtitle_opts.map[ii+1].shortOpt = index_str[ii]; + subtitle_opts.map[ii+1].ivalue = ii; + subtitle_opts.map[ii+1].svalue = subtitle->iso639_2; gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, subtitle->lang, 1, TRUE, - 2, subtitle->iso639_2, + 2, index_str[ii], 3, (gdouble)ii, 4, subtitle->iso639_2, -1); - subtitle_opts.map[ii+2].option = subtitle->lang; - subtitle_opts.map[ii+2].shortOpt = subtitle->iso639_2; - subtitle_opts.map[ii+2].ivalue = ii; - subtitle_opts.map[ii+2].svalue = subtitle->iso639_2; } } else { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, "Closed Captions", + 1, TRUE, + 2, "-2", + 3, -2.0, + 4, "und", + -1); + subtitle_opts.map[1].option = "Closed Captions"; + subtitle_opts.map[1].shortOpt = "-2"; + subtitle_opts.map[1].ivalue = -2; + subtitle_opts.map[1].svalue = "und"; + index_str_init(LANG_TABLE_SIZE-1); for (ii = 0; ii < LANG_TABLE_SIZE; ii++) { - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, ghb_language_table[ii].eng_name, - 1, TRUE, - 2, ghb_language_table[ii].iso639_2, - 3, (gdouble)ii, - 4, ghb_language_table[ii].iso639_2, - -1); subtitle_opts.map[ii+2].option = ghb_language_table[ii].eng_name; - subtitle_opts.map[ii+2].shortOpt = ghb_language_table[ii].iso639_2; + subtitle_opts.map[ii+2].shortOpt = index_str[ii]; subtitle_opts.map[ii+2].ivalue = ii; subtitle_opts.map[ii+2].svalue = ghb_language_table[ii].iso639_2; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, ghb_language_table[ii].eng_name, + 1, TRUE, + 2, index_str[ii], + 3, (gdouble)ii, + 4, ghb_language_table[ii].iso639_2, + -1); } } } @@ -1846,6 +1959,96 @@ ghb_find_audio_track( return track; } +gint +ghb_find_subtitle_track( + gint titleindex, + const gchar *lang, + GHashTable *track_indices) +{ + hb_list_t * list; + hb_title_t * title; + hb_subtitle_t * subtitle; + gint ii; + gint count = 0; + gboolean *used; + + g_debug("find_subtitle_track ()\n"); + if (strcmp(lang, "auto") == 0) + return -1; + if (h_scan == NULL) return -1; + list = hb_get_titles( h_scan ); + title = (hb_title_t*)hb_list_item( list, titleindex ); + if (title != NULL) + { + count = hb_list_count( title->list_subtitle ); + used = g_hash_table_lookup(track_indices, lang); + if (used == NULL) + { + used = g_malloc0(count * sizeof(gboolean)); + g_hash_table_insert(track_indices, g_strdup(lang), used); + } + // Try to find an item that matches the preferred language + for (ii = 0; ii < count; ii++) + { + if (used[ii]) + continue; + + subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii ); + if ((strcmp(lang, subtitle->iso639_2) == 0) || + (strcmp(lang, "und") == 0)) + { + used[ii] = TRUE; + return ii; + } + } + return -1; + } + else + { + count = subtitle_opts.count; + for (ii = 0; ii < count; ii++) + { + if (strcmp(lang, subtitle_opts.map[ii].svalue) == 0) + { + return subtitle_opts.map[ii].ivalue; + } + } + return -1; + } +} + +gint +ghb_pick_subtitle_track(signal_user_data_t *ud) +{ + gint ii, count, track, candidate, first; + GValue *settings, *subtitle_list; + + first = candidate = ghb_settings_combo_int(ud->settings, "SubtitleTrack"); + subtitle_list = ghb_settings_get_value(ud->settings, "subtitle_list"); + count = ghb_array_len(subtitle_list); + for (ii = 0; ii < count; ii++) + { + settings = ghb_array_get_nth(subtitle_list, ii); + track = ghb_settings_combo_int(settings, "SubtitleTrack"); + if (candidate == track) + { + // Already in use, pick another + candidate++; + if (candidate >= subtitle_opts.count) + { + candidate = 0; + } + if (candidate == first) + { + candidate = -1; + break; + } + ii = -1; + } + } + return candidate; +} + static void generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts) { @@ -1888,6 +2091,8 @@ find_combo_table(const gchar *name) gint ghb_lookup_combo_int(const gchar *name, const GValue *gval) { + if (gval == NULL) + return 0; if (strcmp(name, "AudioBitrate") == 0) return lookup_audio_bitrate_int(gval); else if (strcmp(name, "AudioSamplerate") == 0) @@ -1909,6 +2114,8 @@ ghb_lookup_combo_int(const gchar *name, const GValue *gval) gdouble ghb_lookup_combo_double(const gchar *name, const GValue *gval) { + if (gval == NULL) + return 0; if (strcmp(name, "AudioBitrate") == 0) return lookup_audio_bitrate_int(gval); else if (strcmp(name, "AudioSamplerate") == 0) @@ -1930,6 +2137,8 @@ ghb_lookup_combo_double(const gchar *name, const GValue *gval) const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *gval) { + if (gval == NULL) + return NULL; if (strcmp(name, "AudioBitrate") == 0) return lookup_audio_bitrate_option(gval); else if (strcmp(name, "AudioSamplerate") == 0) @@ -1945,11 +2154,38 @@ ghb_lookup_combo_option(const gchar *name, const GValue *gval) return lookup_generic_option(find_combo_table(name), gval); } g_warning("ghb_lookup_combo_int() couldn't find %s", name); - return 0; + return NULL; +} + +const gchar* +ghb_lookup_combo_string(const gchar *name, const GValue *gval) +{ + if (gval == NULL) + return NULL; + if (strcmp(name, "AudioBitrate") == 0) + return lookup_audio_bitrate_option(gval); + else if (strcmp(name, "AudioSamplerate") == 0) + return lookup_audio_rate_option(gval); + else if (strcmp(name, "VideoFramerate") == 0) + return lookup_video_rate_option(gval); + else if (strcmp(name, "AudioMixdown") == 0) + return lookup_mix_option(gval); + else if (strcmp(name, "SourceAudioLang") == 0) + return lookup_audio_lang_option(gval); + else + { + return lookup_generic_string(find_combo_table(name), gval); + } + g_warning("ghb_lookup_combo_int() couldn't find %s", name); + return NULL; } void -ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data, gboolean all) +ghb_update_ui_combo_box( + signal_user_data_t *ud, + const gchar *name, + gint user_data, + gboolean all) { GtkComboBox *combo = NULL; gint signal_id; @@ -1961,7 +2197,7 @@ ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data, // Clearing a combo box causes a rash of "changed" events, even when // the active item is -1 (inactive). To control things, I'm disabling // the event till things are settled down. - combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name)); + combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name)); signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX); if (signal_id > 0) { @@ -1977,52 +2213,52 @@ ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data, } if (all) { - audio_bitrate_opts_set(builder, "AudioBitrate"); - audio_samplerate_opts_set(builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count); - video_rate_opts_set(builder, "VideoFramerate", hb_video_rates, hb_video_rates_count); - mix_opts_set(builder, "AudioMixdown"); - language_opts_set(builder, "SourceAudioLang"); - subtitle_opts_set(builder, "Subtitles", user_data); - title_opts_set(builder, "title"); - audio_track_opts_set(builder, "AudioTrack", user_data); - generic_opts_set(builder, "VideoQualityGranularity", &vqual_granularity_opts); - generic_opts_set(builder, "PicturePAR", &par_opts); - generic_opts_set(builder, "PictureModulus", &alignment_opts); - generic_opts_set(builder, "LoggingLevel", &logging_opts); - generic_opts_set(builder, "FileFormat", &container_opts); - generic_opts_set(builder, "PictureDeinterlace", &deint_opts); - generic_opts_set(builder, "PictureDetelecine", &detel_opts); - generic_opts_set(builder, "PictureDecomb", &decomb_opts); - generic_opts_set(builder, "PictureDenoise", &denoise_opts); - generic_opts_set(builder, "VideoEncoder", &vcodec_opts); - generic_opts_set(builder, "AudioEncoder", &acodec_opts); - generic_opts_set(builder, "x264_direct", &direct_opts); - generic_opts_set(builder, "x264_b_adapt", &badapt_opts); - generic_opts_set(builder, "x264_me", &me_opts); - generic_opts_set(builder, "x264_subme", &subme_opts); - generic_opts_set(builder, "x264_analyse", &analyse_opts); - generic_opts_set(builder, "x264_trellis", &trellis_opts); + audio_bitrate_opts_set(ud->builder, "AudioBitrate"); + audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count); + video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count); + mix_opts_set(ud->builder, "AudioMixdown"); + language_opts_set(ud->builder, "SourceAudioLang"); + subtitle_opts_set(ud, "SubtitleTrack", user_data); + title_opts_set(ud->builder, "title"); + audio_track_opts_set(ud->builder, "AudioTrack", user_data); + generic_opts_set(ud->builder, "VideoQualityGranularity", &vqual_granularity_opts); + generic_opts_set(ud->builder, "PicturePAR", &par_opts); + generic_opts_set(ud->builder, "PictureModulus", &alignment_opts); + generic_opts_set(ud->builder, "LoggingLevel", &logging_opts); + generic_opts_set(ud->builder, "FileFormat", &container_opts); + generic_opts_set(ud->builder, "PictureDeinterlace", &deint_opts); + generic_opts_set(ud->builder, "PictureDetelecine", &detel_opts); + generic_opts_set(ud->builder, "PictureDecomb", &decomb_opts); + generic_opts_set(ud->builder, "PictureDenoise", &denoise_opts); + generic_opts_set(ud->builder, "VideoEncoder", &vcodec_opts); + generic_opts_set(ud->builder, "AudioEncoder", &acodec_opts); + generic_opts_set(ud->builder, "x264_direct", &direct_opts); + generic_opts_set(ud->builder, "x264_b_adapt", &badapt_opts); + generic_opts_set(ud->builder, "x264_me", &me_opts); + generic_opts_set(ud->builder, "x264_subme", &subme_opts); + generic_opts_set(ud->builder, "x264_analyse", &analyse_opts); + generic_opts_set(ud->builder, "x264_trellis", &trellis_opts); } else { if (strcmp(name, "AudioBitrate") == 0) - audio_bitrate_opts_set(builder, "AudioBitrate"); + audio_bitrate_opts_set(ud->builder, "AudioBitrate"); else if (strcmp(name, "AudioSamplerate") == 0) - audio_samplerate_opts_set(builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count); + audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count); else if (strcmp(name, "VideoFramerate") == 0) - video_rate_opts_set(builder, "VideoFramerate", hb_video_rates, hb_video_rates_count); + video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count); else if (strcmp(name, "AudioMixdown") == 0) - mix_opts_set(builder, "AudioMixdown"); + mix_opts_set(ud->builder, "AudioMixdown"); else if (strcmp(name, "SourceAudioLang") == 0) - language_opts_set(builder, "SourceAudioLang"); - else if (strcmp(name, "Subtitles") == 0) - subtitle_opts_set(builder, "Subtitles", user_data); + language_opts_set(ud->builder, "SourceAudioLang"); + else if (strcmp(name, "SubtitleTrack") == 0) + subtitle_opts_set(ud, "SubtitleTrack", user_data); else if (strcmp(name, "title") == 0) - title_opts_set(builder, "title"); + title_opts_set(ud->builder, "title"); else if (strcmp(name, "AudioTrack") == 0) - audio_track_opts_set(builder, "AudioTrack", user_data); + audio_track_opts_set(ud->builder, "AudioTrack", user_data); else - generic_opts_set(builder, name, find_combo_table(name)); + generic_opts_set(ud->builder, name, find_combo_table(name)); } if (handler_id > 0) { @@ -2040,7 +2276,7 @@ init_ui_combo_boxes(GtkBuilder *builder) init_combo_box(builder, "VideoFramerate"); init_combo_box(builder, "AudioMixdown"); init_combo_box(builder, "SourceAudioLang"); - init_combo_box(builder, "Subtitles"); + init_combo_box(builder, "SubtitleTrack"); init_combo_box(builder, "title"); init_combo_box(builder, "AudioTrack"); for (ii = 0; combo_name_map[ii].name != NULL; ii++) @@ -2248,12 +2484,12 @@ ghb_set_default_bitrate_opts(GtkBuilder *builder, gint last_rate) static ghb_status_t hb_status; void -ghb_combo_init(GtkBuilder *builder) +ghb_combo_init(signal_user_data_t *ud) { // Set up the list model for the combos - init_ui_combo_boxes(builder); + init_ui_combo_boxes(ud->builder); // Populate all the combos - ghb_update_ui_combo_box(builder, NULL, 0, TRUE); + ghb_update_ui_combo_box(ud, NULL, 0, TRUE); } void @@ -3699,24 +3935,42 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) { job->x264opts = NULL; } + + const GValue *subtitle_list; gint subtitle; - subtitle = ghb_settings_get_int(js, "subtitle_index"); - if (subtitle == -1) - { - job->indepth_scan = 1; - } - else if (subtitle >= 0) + + subtitle_list = ghb_settings_get_value(js, "subtitle_list"); + count = ghb_array_len(subtitle_list); + for (ii = 0; ii < count; ii++) { - hb_subtitle_t * subt; + GValue *ssettings; + gboolean burned; - subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle); - if (subt != NULL) + ssettings = ghb_array_get_nth(subtitle_list, ii); + + subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack"); + burned = ghb_settings_get_boolean(ssettings, "SubtitleBurned"); + if (subtitle == -1) + { + job->indepth_scan = 1; + } + else if (subtitle >= 0) { - hb_list_add(job->list_subtitle, subt); + hb_subtitle_t * subt; + + subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle); + if (subt != NULL) + { + if (!burned && job->mux == HB_MUX_MKV && + subt->format == PICTURESUB) + { + subt->dest = PASSTHRUSUB; + } + subt->force = ghb_settings_get_boolean(ssettings, "SubtitleForced"); + hb_list_add(job->list_subtitle, subt); + } } } - gboolean forced_subtitles = ghb_settings_get_boolean(js, "SubtitlesForced"); - job->subtitle_force = forced_subtitles; if (job->indepth_scan == 1) { diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h index d946b9224..4517f44f0 100644 --- a/gtk/src/hb-backend.h +++ b/gtk/src/hb-backend.h @@ -98,7 +98,7 @@ void ghb_vquality_range( gint *digits, gboolean *inverted); //const gchar* ghb_get_rate_string(gint rate, gint type); -void ghb_combo_init(GtkBuilder *builder); +void ghb_combo_init(signal_user_data_t *ud); void ghb_backend_init(gint debug); void ghb_backend_close(void); void ghb_add_job(GValue *js, gint unique_id); @@ -136,10 +136,12 @@ void ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate); void ghb_set_default_bitrate_opts(GtkBuilder *builder, gint last_rate); void ghb_grey_combo_options(GtkBuilder *builder); void ghb_update_ui_combo_box( - GtkBuilder *builder, const gchar *name, gint user_data, gboolean all); + signal_user_data_t *ud, const gchar *name, gint user_data, gboolean all); gint ghb_find_audio_track( - gint titleindex, const gchar *lang, - gint acodec, GHashTable *track_indices); + gint titleindex, const gchar *lang, gint acodec, GHashTable *track_indices); +gint ghb_find_subtitle_track( + gint titleindex, const gchar *lang, GHashTable *track_indices); +gint ghb_pick_subtitle_track(signal_user_data_t *ud); gint ghb_longest_title(void); gchar* ghb_build_x264opts_string(GValue *settings); GdkPixbuf* ghb_get_preview_image( @@ -148,6 +150,8 @@ GdkPixbuf* ghb_get_preview_image( gint ghb_calculate_target_bitrate(GValue *settings, gint titleindex); gchar* ghb_dvd_volname(const gchar *device); gint ghb_get_title_number(gint titleindex); +gint ghb_subtitle_track_source(signal_user_data_t *ud, gint track); +const char* ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track); gboolean ghb_validate_vquality(GValue *settings); gboolean ghb_validate_audio(signal_user_data_t *ud); @@ -155,9 +159,10 @@ gboolean ghb_validate_video(signal_user_data_t *ud); gboolean ghb_validate_filters(signal_user_data_t *ud); gboolean ghb_validate_filter_string(const gchar *str, gint max_fields); void ghb_hb_cleanup(gboolean partial); -gint ghb_lookup_combo_int(const gchar *name, const GValue *acodec); -gdouble ghb_lookup_combo_double(const gchar *name, const GValue *acodec); -const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *acodec); +gint ghb_lookup_combo_int(const gchar *name, const GValue *gval); +gdouble ghb_lookup_combo_double(const gchar *name, const GValue *gval); +const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *gval); +const gchar* ghb_lookup_combo_string(const gchar *name, const GValue *gval); gchar* ghb_get_tmp_dir(); #endif // _HBBACKEND_H_ diff --git a/gtk/src/internal_defaults.xml b/gtk/src/internal_defaults.xml index eb858d019..be58588e0 100644 --- a/gtk/src/internal_defaults.xml +++ b/gtk/src/internal_defaults.xml @@ -89,6 +89,9 @@ <key>audio_list</key> <array> </array> + <key>subtitle_list</key> + <array> + </array> <key>vquality_type_bitrate</key> <false /> <key>vquality_type_constant</key> @@ -222,8 +225,6 @@ <integer>0</integer> <key>PictureWidth</key> <integer>0</integer> - <key>SubtitlesForced</key> - <true /> <key>VideoFramerate</key> <string>source</string> <key>VideoGrayScale</key> @@ -263,8 +264,17 @@ <integer>1</integer> <key>SourceAudioLang</key> <string>und</string> - <key>Subtitles</key> - <string>none</string> + <key>SubtitleList</key> + <array> + <dict> + <key>SubtitleLanguage</key> + <string>und</string> + <key>SubtitleForced</key> + <false /> + <key>SubtitleBurned</key> + <true /> + </dict> + </array> <key>VideoTurboTwoPass</key> <false /> <key>UsesPictureFilters</key> diff --git a/gtk/src/main.c b/gtk/src/main.c index 505142be5..d7a15c1b1 100644 --- a/gtk/src/main.c +++ b/gtk/src/main.c @@ -376,6 +376,67 @@ bind_audio_tree_model (signal_user_data_t *ud) g_debug("Done\n"); } +extern G_MODULE_EXPORT void subtitle_list_selection_changed_cb(void); +extern G_MODULE_EXPORT void subtitle_forced_toggled_cb(void); +extern G_MODULE_EXPORT void subtitle_burned_toggled_cb(void); + +// Create and bind the tree model to the tree view for the subtitle track list +// Also, connect up the signal that lets us know the selection has changed +static void +bind_subtitle_tree_model (signal_user_data_t *ud) +{ + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + GtkListStore *treestore; + GtkTreeView *treeview; + GtkTreeSelection *selection; + GtkWidget *widget; + + g_debug("bind_subtitle_tree_model ()\n"); + treeview = GTK_TREE_VIEW(GHB_WIDGET (ud->builder, "subtitle_list")); + selection = gtk_tree_view_get_selection (treeview); + // 5 columns in model. 4 are visible, the other 1 is for storing + // values that I need + treestore = gtk_list_store_new(5, + G_TYPE_STRING, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(treestore)); + + cell = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Track"), cell, "text", 0, NULL); + gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); + + cell = gtk_cell_renderer_toggle_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Forced Only"), cell, "active", 1, NULL); + gtk_tree_view_column_set_max_width (column, 50); + gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); + g_signal_connect(cell, "toggled", subtitle_forced_toggled_cb, ud); + + cell = gtk_cell_renderer_toggle_new(); + gtk_cell_renderer_toggle_set_radio(GTK_CELL_RENDERER_TOGGLE(cell), TRUE); + column = gtk_tree_view_column_new_with_attributes( + _("Burned In"), cell, "active", 2, NULL); + gtk_tree_view_column_set_max_width (column, 50); + gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); + g_signal_connect(cell, "toggled", subtitle_burned_toggled_cb, ud); + + cell = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Type"), cell, "text", 3, NULL); + gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); + + + g_signal_connect(selection, "changed", subtitle_list_selection_changed_cb, ud); + // Need to disable remove and update buttons since there are initially + // no selections + widget = GHB_WIDGET (ud->builder, "subtitle_remove"); + gtk_widget_set_sensitive(widget, FALSE); + g_debug("Done\n"); +} + extern G_MODULE_EXPORT void presets_list_selection_changed_cb(void); extern G_MODULE_EXPORT void presets_drag_cb(void); extern G_MODULE_EXPORT void presets_drag_motion_cb(void); @@ -642,12 +703,13 @@ main (int argc, char *argv[]) buffer = gtk_text_view_get_buffer (textview); g_signal_connect(buffer, "changed", (GCallback)x264_entry_changed_cb, ud); - ghb_combo_init(ud->builder); + ghb_combo_init(ud); g_debug("ud %p\n", ud); g_debug("ud->builder %p\n", ud->builder); bind_audio_tree_model(ud); + bind_subtitle_tree_model(ud); bind_presets_tree_model(ud); bind_queue_tree_model(ud); bind_chapter_tree_model(ud); diff --git a/gtk/src/presets.c b/gtk/src/presets.c index 25a5e96ce..35f7b9c4b 100644 --- a/gtk/src/presets.c +++ b/gtk/src/presets.c @@ -20,6 +20,7 @@ #include "settings.h" #include "callbacks.h" #include "audiohandler.h" +#include "subtitlehandler.h" #include "hb-backend.h" #include "plist.h" #include "resources.h" @@ -2057,15 +2058,25 @@ export_value_xlat(GValue *dict) gval = export_value_xlat2(denoise_xlat, lin_val, G_TYPE_INT); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); - key = "Subtitles"; - lin_val = ghb_dict_lookup(dict, key); - gval = export_subtitle_xlat2(lin_val); - if (gval) - ghb_dict_insert(dict, g_strdup(key), gval); + + GValue *slist; + GValue *sdict; + gint count, ii; + + slist = ghb_dict_lookup(dict, "SubtitleList"); + count = ghb_array_len(slist); + for (ii = 0; ii < count; ii++) + { + sdict = ghb_array_get_nth(slist, ii); + key = "SubtitleLanguage"; + lin_val = ghb_dict_lookup(sdict, key); + gval = export_subtitle_xlat2(lin_val); + if (gval) + ghb_dict_insert(sdict, g_strdup(key), gval); + } GValue *alist; GValue *adict; - gint count, ii; alist = ghb_dict_lookup(dict, "AudioList"); count = ghb_array_len(alist); @@ -2132,13 +2143,34 @@ import_value_xlat2( return gval; } } - //g_warning("Can't map value: (%s)", str); g_free(str); } else { - g_warning("Bad key: (%s)", key); - return NULL; + gint ii; + gchar *str; + GValue *sval; + + str = ghb_value_string(mac_val); + for (ii = 0; value_map[ii].mac_val; ii++) + { + if (strcmp(str, value_map[ii].mac_val) == 0) + { + sval = ghb_string_value_new(value_map[ii].lin_val); + g_free(str); + gval = ghb_value_new(G_VALUE_TYPE(mac_val)); + if (!g_value_transform(sval, gval)) + { + g_warning("can't transform"); + ghb_value_free(gval); + ghb_value_free(sval); + return NULL; + } + ghb_value_free(sval); + return gval; + } + } + g_free(str); } return NULL; } @@ -2185,19 +2217,82 @@ import_value_xlat(GValue *dict) gval = import_value_xlat2(defaults, denoise_xlat, key, mac_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); - key = "Subtitles"; - mac_val = ghb_dict_lookup(dict, key); - gval = import_subtitle_xlat2(mac_val); - if (gval) - ghb_dict_insert(dict, g_strdup(key), gval); + + GValue *sdeflist; + GValue *sdefaults; + GValue *slist; + GValue *sdict; + gint count, ii; + + sdeflist = ghb_dict_lookup(defaults, "SubtitleList"); + if (sdeflist) + { + slist = ghb_dict_lookup(dict, "SubtitleList"); + if (slist) + { + sdefaults = ghb_array_get_nth(sdeflist, 0); + count = ghb_array_len(slist); + for (ii = 0; ii < count; ii++) + { + sdict = ghb_array_get_nth(slist, ii); + key = "SubtitleLanguage"; + mac_val = ghb_dict_lookup(sdict, key); + gval = import_subtitle_xlat2(mac_val); + if (gval) + ghb_dict_insert(sdict, g_strdup(key), gval); + } + + } + else + { + key = "Subtitles"; + mac_val = ghb_dict_lookup(dict, key); + if (mac_val) + { + gchar *lang; + + gval = import_subtitle_xlat2(mac_val); + lang = ghb_value_string(gval); + if (lang && strcmp(lang, "none") != 0 && !slist) + { + slist = ghb_array_value_new(8); + sdict = ghb_dict_value_new(); + ghb_dict_insert(dict, g_strdup("SubtitleList"), slist); + ghb_array_append(slist, sdict); + ghb_dict_insert(sdict, g_strdup("SubtitleLanguage"), gval); + gval = ghb_dict_lookup(dict, "SubtitlesForced"); + if (gval != NULL) + { + ghb_dict_insert(sdict, g_strdup("SubtitleForced"), + ghb_value_dup(gval)); + } + else + { + ghb_dict_insert(sdict, g_strdup("SubtitleForced"), + ghb_boolean_value_new(FALSE)); + } + ghb_dict_insert(sdict, g_strdup("SubtitleBurned"), + ghb_boolean_value_new(TRUE)); + } + else + { + ghb_value_free(gval); + } + if (lang) + g_free(lang); + } + } + } + ghb_dict_remove(dict, "Subtitles"); + ghb_dict_remove(dict, "SubtitlesForced"); + GValue *alist; GValue *adict; GValue *adefaults; GValue *adeflist; - gint count, ii; - adeflist = ghb_dict_lookup(dict, "AudioList"); + adeflist = ghb_dict_lookup(defaults, "AudioList"); if (adeflist) { adefaults = ghb_array_get_nth(adeflist, 0); @@ -2847,6 +2942,16 @@ update_audio_presets(signal_user_data_t *ud) ghb_settings_set_value(ud->settings, "AudioList", audio_list); } +static void +update_subtitle_presets(signal_user_data_t *ud) +{ + g_debug("update_subtitle_presets"); + const GValue *subtitle_list; + + subtitle_list = ghb_settings_get_value(ud->settings, "subtitle_list"); + ghb_settings_set_value(ud->settings, "SubtitleList", subtitle_list); +} + void enforce_preset_type(signal_user_data_t *ud, const GValue *path) { @@ -2940,6 +3045,7 @@ presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) { // Construct the audio settings presets from the current audio list update_audio_presets(ud); + update_subtitle_presets(ud); settings_save(ud, dest); } ghb_value_free(dest); @@ -3435,6 +3541,7 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_ gint titleindex; titleindex = ghb_settings_combo_int(ud->settings, "title"); ghb_set_pref_audio(titleindex, ud); + ghb_set_pref_subtitle(titleindex, ud); ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE); if (ghb_get_title_info (&tinfo, titleindex)) { diff --git a/gtk/src/queuehandler.c b/gtk/src/queuehandler.c index 8ff54419a..1ac36ca89 100644 --- a/gtk/src/queuehandler.c +++ b/gtk/src/queuehandler.c @@ -646,7 +646,6 @@ queue_add(signal_user_data_t *ud) GValue *settings; gint titleindex; gint titlenum; - gint sub; g_debug("queue_add ()"); if (!validate_settings(ud)) @@ -663,9 +662,6 @@ queue_add(signal_user_data_t *ud) ud->queue = ghb_array_value_new(32); // Make a copy of current settings to be used for the new job settings = ghb_value_dup(ud->settings); - sub = ghb_settings_combo_int(settings, "Subtitles"); - ghb_settings_set_int(settings, "subtitle_index", sub); - ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING); ghb_settings_set_int(settings, "job_unique_id", 0); titleindex = ghb_settings_combo_int(settings, "title"); diff --git a/gtk/src/settings.c b/gtk/src/settings.c index c6657707f..41dd26ba2 100644 --- a/gtk/src/settings.c +++ b/gtk/src/settings.c @@ -170,6 +170,12 @@ ghb_settings_combo_option(const GValue *settings, const gchar *key) return ghb_lookup_combo_option(key, ghb_settings_get_value(settings, key)); } +const gchar* +ghb_settings_combo_string(const GValue *settings, const gchar *key) +{ + return ghb_lookup_combo_string(key, ghb_settings_get_value(settings, key)); +} + // Map widget names to setting keys // Widgets that map to settings have names // of this format: s_<setting key> diff --git a/gtk/src/settings.h b/gtk/src/settings.h index 8c2cac821..072baf07a 100644 --- a/gtk/src/settings.h +++ b/gtk/src/settings.h @@ -86,6 +86,7 @@ gchar* ghb_settings_get_string(const GValue *settings, const gchar *key); gint ghb_settings_combo_int(const GValue *settings, const gchar *key); gdouble ghb_settings_combo_double(const GValue *settings, const gchar *key); const gchar* ghb_settings_combo_option(const GValue *settings, const gchar *key); +const gchar* ghb_settings_combo_string(const GValue *settings, const gchar *key); GValue* ghb_widget_value(GtkWidget *widget); gchar* ghb_widget_string(GtkWidget *widget); diff --git a/libhb/common.h b/libhb/common.h index 516318907..224b40c78 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -238,7 +238,6 @@ struct hb_job_s int indepth_scan; hb_subtitle_t ** select_subtitle; - int subtitle_force; char * native_language; int angle; // dvd angle to encode @@ -445,6 +444,7 @@ struct hb_subtitle_s enum subtype { PICTURESUB, TEXTSUB } format; enum subsource { VOBSUB, SRTSUB, CC608SUB, CC708SUB } source; enum subdest { RENDERSUB, PASSTHRUSUB } dest; + int force; char lang[1024]; char iso639_2[4]; uint8_t type; /* Closed Caption, Childrens, Directors etc */ @@ -639,6 +639,9 @@ struct hb_work_object_s /* Pointer hb_audio_t so we have access to the info in the audio worker threads. */ hb_audio_t * audio; + /* Pointer hb_subtitle_t so we have access to the info in the subtitle worker threads. */ + hb_subtitle_t * subtitle; + hb_work_private_t * private_data; hb_thread_t * thread; diff --git a/libhb/decvobsub.c b/libhb/decvobsub.c index fd1f89179..e5633d54d 100644 --- a/libhb/decvobsub.c +++ b/libhb/decvobsub.c @@ -8,27 +8,27 @@ struct hb_work_private_s { - hb_job_t * job; - - uint8_t buf[0xFFFF]; - int size_sub; - int size_got; - int size_rle; - int64_t pts; - int64_t pts_start; - int64_t pts_stop; - int pts_forced; - int x; - int y; - int width; - int height; - int stream_id; - - int offsets[2]; - uint8_t lum[4]; - uint8_t chromaU[4]; - uint8_t chromaV[4]; - uint8_t alpha[4]; + hb_job_t * job; + + hb_buffer_t * buf; + int size_sub; + int size_got; + int size_rle; + int64_t pts; + int64_t pts_start; + int64_t pts_stop; + int pts_forced; + int x; + int y; + int width; + int height; + int stream_id; + + int offsets[2]; + uint8_t lum[4]; + uint8_t chromaU[4]; + uint8_t chromaV[4]; + uint8_t alpha[4]; }; static hb_buffer_t * Decode( hb_work_object_t * ); @@ -76,7 +76,10 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, pv->size_sub = size_sub; pv->size_rle = size_rle; - memcpy( pv->buf, in->data, in->size ); + pv->buf = hb_buffer_init( 0xFFFF ); + memcpy( pv->buf->data, in->data, in->size ); + pv->buf->id = in->id; + pv->buf->sequence = in->sequence; pv->size_got = in->size; pv->pts = in->start; } @@ -86,7 +89,9 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, /* We are waiting for the end of the current subtitle */ if( in->size <= pv->size_sub - pv->size_got ) { - memcpy( pv->buf + pv->size_got, in->data, in->size ); + memcpy( pv->buf->data + pv->size_got, in->data, in->size ); + pv->buf->id = in->id; + pv->buf->sequence = in->sequence; pv->size_got += in->size; if( in->start >= 0 ) { @@ -99,11 +104,14 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, if( pv->size_sub && pv->size_sub == pv->size_got ) { + pv->buf->size = pv->size_sub; + /* We got a complete subtitle, decode it */ *buf_out = Decode( w ); if( buf_out && *buf_out ) { + (*buf_out)->id = in->id; (*buf_out)->sequence = in->sequence; } @@ -145,6 +153,7 @@ static void ParseControls( hb_work_object_t * w ) hb_job_t * job = pv->job; hb_title_t * title = job->title; hb_subtitle_t * subtitle; + uint8_t * buf = pv->buf->data; int i, n; int command; @@ -161,12 +170,12 @@ static void ParseControls( hb_work_object_t * w ) for( i = pv->size_rle; ; ) { - date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2; - next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2; + date = ( buf[i] << 8 ) | buf[i+1]; i += 2; + next = ( buf[i] << 8 ) | buf[i+1]; i += 2; for( ;; ) { - command = pv->buf[i++]; + command = buf[i++]; /* * There are eight commands available for @@ -224,10 +233,10 @@ static void ParseControls( hb_work_object_t * w ) int colors[4]; int j; - colors[0] = (pv->buf[i+0]>>4)&0x0f; - colors[1] = (pv->buf[i+0])&0x0f; - colors[2] = (pv->buf[i+1]>>4)&0x0f; - colors[3] = (pv->buf[i+1])&0x0f; + colors[0] = (buf[i+0]>>4)&0x0f; + colors[1] = (buf[i+0])&0x0f; + colors[2] = (buf[i+1]>>4)&0x0f; + colors[3] = (buf[i+1])&0x0f; for( j = 0; j < 4; j++ ) { @@ -267,10 +276,10 @@ static void ParseControls( hb_work_object_t * w ) */ uint8_t alpha[4]; - alpha[3] = (pv->buf[i+0]>>4)&0x0f; - alpha[2] = (pv->buf[i+0])&0x0f; - alpha[1] = (pv->buf[i+1]>>4)&0x0f; - alpha[0] = (pv->buf[i+1])&0x0f; + alpha[3] = (buf[i+0]>>4)&0x0f; + alpha[2] = (buf[i+0])&0x0f; + alpha[1] = (buf[i+1]>>4)&0x0f; + alpha[0] = (buf[i+1])&0x0f; int lastAlpha = pv->alpha[3] + pv->alpha[2] + pv->alpha[1] + pv->alpha[0]; @@ -296,17 +305,17 @@ static void ParseControls( hb_work_object_t * w ) } case 0x05: // 0x05 - SET_DAREA - defines the display area { - pv->x = (pv->buf[i+0]<<4) | ((pv->buf[i+1]>>4)&0x0f); - pv->width = (((pv->buf[i+1]&0x0f)<<8)| pv->buf[i+2]) - pv->x + 1; - pv->y = (pv->buf[i+3]<<4)| ((pv->buf[i+4]>>4)&0x0f); - pv->height = (((pv->buf[i+4]&0x0f)<<8)| pv->buf[i+5]) - pv->y + 1; + pv->x = (buf[i+0]<<4) | ((buf[i+1]>>4)&0x0f); + pv->width = (((buf[i+1]&0x0f)<<8)| buf[i+2]) - pv->x + 1; + pv->y = (buf[i+3]<<4)| ((buf[i+4]>>4)&0x0f); + pv->height = (((buf[i+4]&0x0f)<<8)| buf[i+5]) - pv->y + 1; i += 6; break; } case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses { - pv->offsets[0] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2; - pv->offsets[1] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2; + pv->offsets[0] = ( buf[i] << 8 ) | buf[i+1]; i += 2; + pv->offsets[1] = ( buf[i] << 8 ) | buf[i+1]; i += 2; break; } } @@ -475,7 +484,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) /* Get infos about the subtitle */ ParseControls( w ); - if( job->indepth_scan || ( job->subtitle_force && pv->pts_forced == 0 ) ) + if( job->indepth_scan || ( w->subtitle->force && pv->pts_forced == 0 ) ) { /* * Don't encode subtitles when doing a scan. @@ -486,11 +495,18 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) return NULL; } + if (w->subtitle->dest == PASSTHRUSUB) + { + pv->buf->start = pv->pts_start; + pv->buf->stop = pv->pts_stop; + return pv->buf; + } + /* Do the actual decoding now */ buf_raw = malloc( ( pv->width * pv->height ) * 4 ); #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \ -( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \ +( pv->buf->data[((*offset)>>1)] & 0xF ) : ( pv->buf->data[((*offset)>>1)] >> 4 ) ) ); \ (*offset)++ offsets[0] = pv->offsets[0] * 2; @@ -547,6 +563,8 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) } } + hb_buffer_close( &pv->buf ); + /* Crop subtitle (remove transparent borders) */ buf = CropSubtitle( w, buf_raw ); diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 5fde4cba7..515de1ee0 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -619,11 +619,15 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t ) lang = lang_for_code( ifo->vtsi_mat->vts_subp_attr[i].lang_code ); subtitle = calloc( sizeof( hb_subtitle_t ), 1 ); + subtitle->track = i+1; subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd; snprintf( subtitle->lang, sizeof( subtitle->lang ), "%s", strlen(lang->native_name) ? lang->native_name : lang->eng_name); snprintf( subtitle->iso639_2, sizeof( subtitle->iso639_2 ), "%s", lang->iso639_2); + subtitle->format = PICTURESUB; + subtitle->source = VOBSUB; + subtitle->dest = RENDERSUB; // By default render (burn-in) the VOBSUB. subtitle->type = lang_extension; diff --git a/libhb/encvobsub.c b/libhb/encvobsub.c index ee49d7ad6..20a9879d6 100644 --- a/libhb/encvobsub.c +++ b/libhb/encvobsub.c @@ -26,9 +26,15 @@ int encsubInit( hb_work_object_t * w, hb_job_t * job ) int encsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { - hb_work_private_t * pv = w->private_data; hb_buffer_t * in = *buf_in; + if (w->subtitle->source != VOBSUB) + { + // Invalid source, send EOF, this shouldn't ever happen + hb_log("encvobsub: invalid subtitle source"); + hb_buffer_close( buf_in ); + *buf_out = hb_buffer_init(0); + } if ( in->size <= 0 ) { /* EOF on input stream - send it downstream & say that we're done */ @@ -38,10 +44,14 @@ int encsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, } /* - * Don't do anything at present, just pass the buffer on. + * Not much to do, just pass the buffer on. + * Some day, we may re-encode bd subtitles here ;) */ - *buf_out = in; - *buf_in = NULL; + if (buf_out) + { + *buf_out = in; + *buf_in = NULL; + } return HB_WORK_OK; } diff --git a/libhb/fifo.c b/libhb/fifo.c index c756f5673..7337874bf 100644 --- a/libhb/fifo.c +++ b/libhb/fifo.c @@ -191,6 +191,7 @@ void hb_buffer_close( hb_buffer_t ** _b ) if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) ) { hb_fifo_push_head( buffer_pool, b ); + *_b = NULL; return; } /* either the pool is full or this size doesn't use a pool - free the buf */ diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index c3d627979..04f9ae595 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -34,6 +34,27 @@ struct hb_mux_data_s int sub_format; }; +static int yuv2rgb(int yuv) +{ + double y, Cr, Cb; + int r, g, b; + + y = (yuv >> 16) & 0xff; + Cr = (yuv >> 8) & 0xff; + Cb = (yuv) & 0xff; + + r = 1.164 * (y - 16) + 2.018 * (Cb - 128); + g = 1.164 * (y - 16) - 0.813 * (Cr - 128) - 0.391 * (Cb - 128); + b = 1.164 * (y - 16) + 1.596 * (Cr - 128); + r = (r < 0) ? 0 : r; + g = (g < 0) ? 0 : g; + b = (b < 0) ? 0 : b; + r = (r > 255) ? 255 : r; + g = (g > 255) ? 255 : g; + b = (b > 255) ? 255 : b; + return (r << 16) | (g << 8) | b; +} + /********************************************************************** * MKVInit ********************************************************************** @@ -48,7 +69,7 @@ static int MKVInit( hb_mux_object_t * m ) uint8_t *avcC = NULL; uint8_t default_track_flag = 1; - int avcC_len, i; + int avcC_len, i, j; ogg_packet *ogg_headers[3]; mk_TrackConfig *track; @@ -261,7 +282,7 @@ static int MKVInit( hb_mux_object_t * m ) for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) { hb_subtitle_t * subtitle; - uint32_t * palette; + uint32_t rgb[16]; char subidx[2048]; int len; @@ -270,28 +291,39 @@ static int MKVInit( hb_mux_object_t * m ) continue; memset(track, 0, sizeof(mk_TrackConfig)); + switch (subtitle->format) + { + case PICTURESUB: + track->codecID = MK_SUBTITLE_VOBSUB; + for (j = 0; j < 16; j++) + rgb[j] = yuv2rgb(title->palette[j]); + len = snprintf(subidx, 2048, subidx_fmt, + title->width, title->height, + 0, 0, "OFF", + rgb[0], rgb[1], rgb[2], rgb[3], + rgb[4], rgb[5], rgb[6], rgb[7], + rgb[8], rgb[9], rgb[10], rgb[11], + rgb[12], rgb[13], rgb[14], rgb[15]); + track->codecPrivate = subidx; + track->codecPrivateSize = len + 1; + break; + case TEXTSUB: + track->codecID = MK_SUBTITLE_UTF8; + break; + default: + continue; + } mux_data = calloc(1, sizeof( hb_mux_data_t ) ); subtitle->mux_data = mux_data; mux_data->subtitle = 1; mux_data->sub_format = subtitle->format; - palette = title->palette; - len = snprintf(subidx, 2048, subidx_fmt, title->width, title->height, - 0, 0, "OFF", - palette[0], palette[1], palette[2], palette[3], - palette[4], palette[5], palette[6], palette[7], - palette[8], palette[9], palette[10], palette[11], - palette[12], palette[13], palette[14], palette[15]); - track->codecPrivate = subidx; - track->codecPrivateSize = len + 1; - track->codecID = MK_SUBTITLE_VOBSUB; track->flagEnabled = 1; track->trackType = MK_TRACK_SUBTITLE; track->language = subtitle->iso639_2; mux_data->track = mk_createTrack(m->file, track); - } if( mk_writeHeader( m->file, "HandBrake " HB_PROJECT_VERSION) < 0 ) @@ -362,19 +394,33 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, *job->die = 1; } mk_addFrameData(m->file, mux_data->track, op->packet, op->bytes); - mk_setFrameFlags(m->file, mux_data->track, timecode, 1); + mk_setFrameFlags(m->file, mux_data->track, timecode, 1, 0); return 0; } } else if ( mux_data->subtitle ) { timecode = buf->start * TIMECODE_SCALE; + if( mk_startFrame(m->file, mux_data->track) < 0) + { + hb_error( "Failed to write frame to output file, Disk Full?" ); + *job->die = 1; + } if( mux_data->sub_format == TEXTSUB ) { - hb_log("MuxMKV: Text Sub:%lld: %s", buf->start, buf->data); - // TODO: add CC data to track - return 0; + uint64_t duration; + + duration = buf->stop * TIMECODE_SCALE - timecode; + mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); + mk_setFrameFlags(m->file, mux_data->track, timecode, 1, duration); } + else + { + mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); + mk_setFrameFlags(m->file, mux_data->track, timecode, 1, 0); + } + mk_flushFrame(m->file, mux_data->track); + return 0; } else { @@ -391,7 +437,7 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, *job->die = 1; } mk_addFrameData(m->file, mux_data->track, op->packet, op->bytes); - mk_setFrameFlags(m->file, mux_data->track, timecode, 1); + mk_setFrameFlags(m->file, mux_data->track, timecode, 1, 0); return 0; } } @@ -403,7 +449,10 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); mk_setFrameFlags(m->file, mux_data->track, timecode, - ((job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data) ? (buf->frametype == HB_FRAME_IDR) : ((buf->frametype & HB_FRAME_KEY) != 0)) ); + ((job->vcodec == HB_VCODEC_X264 && + mux_data == job->mux_data) ? + (buf->frametype == HB_FRAME_IDR) : + ((buf->frametype & HB_FRAME_KEY) != 0)), 0 ); return 0; } diff --git a/libhb/reader.c b/libhb/reader.c index dd478151b..c865ea85f 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -527,7 +527,7 @@ static hb_fifo_t ** GetFifoForId( hb_job_t * job, int id ) subtitle = hb_list_item( title->list_subtitle, i ); if (id == subtitle->id) { subtitle->hits++; - if( !job->indepth_scan || job->subtitle_force ) + if( !job->indepth_scan || subtitle->force ) { /* * Pass the subtitles to be processed if we are not scanning, or if diff --git a/libhb/sync.c b/libhb/sync.c index 1001ed50c..d76907987 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -485,7 +485,9 @@ static void SyncVideo( hb_work_object_t * w ) when the second one starts */ sub2 = hb_fifo_see2( subtitle->fifo_raw ); if( sub2 && sub->stop > sub2->start ) + { sub->stop = sub2->start; + } // hb_log("0x%x: video seq: %lld subtitle sequence: %lld", // sub, cur->sequence, sub->sequence); @@ -508,120 +510,160 @@ static void SyncVideo( hb_work_object_t * w ) * and we'll deal with it in the next block of * code. */ - break; - } - - /* - * The subtitle is older than this picture, trash it - */ - sub = hb_fifo_get( subtitle->fifo_raw ); - hb_buffer_close( &sub ); - } - - if( sub && sub->size == 0 ) - { - /* - * Continue immediately on subtitle EOF - */ - break; - } - /* - * There is a valid subtitle, is it time to display it? - */ - if( sub ) - { - if( sub->stop > sub->start) - { /* - * Normal subtitle which ends after it starts, check to - * see that the current video is between the start and end. + * There is a valid subtitle, is it time to display it? */ - if( cur->start > sub->start && - cur->start < sub->stop ) + if( sub->stop > sub->start) { /* - * We should be playing this, so leave the - * subtitle in place. - * - * fall through to display + * Normal subtitle which ends after it starts, + * check to see that the current video is between + * the start and end. */ - if( ( sub->stop - sub->start ) < ( 3 * 90000 ) ) + if( cur->start > sub->start && + cur->start < sub->stop ) { /* - * Subtitle is on for less than three seconds, extend - * the time that it is displayed to make it easier - * to read. Make it 3 seconds or until the next - * subtitle is displayed. - * - * This is in response to Indochine which only - * displays subs for 1 second - too fast to read. - */ - sub->stop = sub->start + ( 3 * 90000 ); + * We should be playing this, so leave the + * subtitle in place. + * + * fall through to display + */ + if( ( sub->stop - sub->start ) < ( 3 * 90000 ) ) + { + /* + * Subtitle is on for less than three + * seconds, extend the time that it is + * displayed to make it easier to read. + * Make it 3 seconds or until the next + * subtitle is displayed. + * + * This is in response to Indochine which + * only displays subs for 1 second - + * too fast to read. + */ + sub->stop = sub->start + ( 3 * 90000 ); - sub2 = hb_fifo_see2( subtitle->fifo_raw ); + sub2 = hb_fifo_see2( subtitle->fifo_raw ); - if( sub2 && sub->stop > sub2->start ) - { - sub->stop = sub2->start; + if( sub2 && sub->stop > sub2->start ) + { + sub->stop = sub2->start; + } } } + else + { + /* + * Defer until the play point is within + * the subtitle + */ + sub = NULL; + } } else { /* - * Defer until the play point is within the subtitle + * The end of the subtitle is less than the start, + * this is a sign of a PTS discontinuity. */ - sub = NULL; + if( sub->start > cur->start ) + { + /* + * we haven't reached the start time yet, or + * we have jumped backwards after having + * already started this subtitle. + */ + if( cur->start < sub->stop ) + { + /* + * We have jumped backwards and so should + * continue displaying this subtitle. + * + * fall through to display. + */ + } + else + { + /* + * Defer until the play point is + * within the subtitle + */ + sub = NULL; + } + } else { + /* + * Play this subtitle as the start is + * greater than our video point. + * + * fall through to display/ + */ + } } + break; } else { + /* - * The end of the subtitle is less than the start, this is a - * sign of a PTS discontinuity. + * The subtitle is older than this picture, trash it */ - if( sub->start > cur->start ) + sub = hb_fifo_get( subtitle->fifo_raw ); + hb_buffer_close( &sub ); + } + } + + /* If we have a subtitle for this picture, copy it */ + /* FIXME: we should avoid this memcpy */ + if( sub ) + { + if( sub->size > 0 ) + { + if( subtitle->dest == RENDERSUB ) { - /* - * we haven't reached the start time yet, or - * we have jumped backwards after having - * already started this subtitle. - */ - if( cur->start < sub->stop ) - { - /* - * We have jumped backwards and so should - * continue displaying this subtitle. - * - * fall through to display. - */ - } - else + if ( cur->sub == NULL ) { /* - * Defer until the play point is within the subtitle + * Tack onto the video buffer for rendering */ - sub = NULL; + cur->sub = hb_buffer_init( sub->size ); + cur->sub->x = sub->x; + cur->sub->y = sub->y; + cur->sub->width = sub->width; + cur->sub->height = sub->height; + memcpy( cur->sub->data, sub->data, sub->size ); } } else { /* - * Play this subtitle as the start is greater than our - * video point. - * - * fall through to display/ + * Pass-Through, pop it off of the raw queue, + * rewrite times and make it available to be + * reencoded. */ + uint64_t sub_duration; + sub = hb_fifo_get( subtitle->fifo_raw ); + sub_duration = sub->stop - sub->start; + sub->start = cur->start; + buf_tmp = hb_fifo_see( job->fifo_raw ); + int64_t duration = buf_tmp->start - cur->start; + sub->stop = sub->start + duration; + hb_fifo_push( subtitle->fifo_sync, sub ); + } + } else { + /* + * EOF - consume for rendered, else pass through + */ + if( subtitle->dest == RENDERSUB ) + { + sub = hb_fifo_get( subtitle->fifo_raw ); + hb_buffer_close( &sub ); + } else { + sub = hb_fifo_get( subtitle->fifo_raw ); + hb_fifo_push( subtitle->fifo_out, sub ); } } } } - if( sub ) - { - /* - * Got a sub to display... - */ - break; - } } // end subtitles /* @@ -639,6 +681,7 @@ static void SyncVideo( hb_work_object_t * w ) */ buf_tmp = cur; pv->cur = cur = hb_fifo_get( job->fifo_raw ); + cur->sub = NULL; pv->next_pts = cur->start; int64_t duration = cur->start - buf_tmp->start; if ( duration <= 0 ) @@ -659,51 +702,6 @@ static void SyncVideo( hb_work_object_t * w ) pv->chap_mark = 0; } - /* If we have a subtitle for this picture, copy it */ - /* FIXME: we should avoid this memcpy */ - if( sub && subtitle && - subtitle->format == PICTURESUB ) - { - if( sub->size > 0 ) - { - if( subtitle->dest == RENDERSUB ) - { - /* - * Tack onto the video buffer for rendering - */ - buf_tmp->sub = hb_buffer_init( sub->size ); - buf_tmp->sub->x = sub->x; - buf_tmp->sub->y = sub->y; - buf_tmp->sub->width = sub->width; - buf_tmp->sub->height = sub->height; - memcpy( buf_tmp->sub->data, sub->data, sub->size ); - } else { - /* - * Pass-Through, pop it off of the raw queue, rewrite times and - * make it available to be reencoded. - */ - uint64_t sub_duration; - sub = hb_fifo_get( subtitle->fifo_raw ); - sub_duration = sub->stop - sub->start; - sub->start = buf_tmp->start; - sub->stop = sub->start + duration; - hb_fifo_push( subtitle->fifo_sync, sub ); - } - } else { - /* - * EOF - consume for rendered, else pass through - */ - if( subtitle->dest == RENDERSUB ) - { - sub = hb_fifo_get( subtitle->fifo_raw ); - hb_buffer_close( &sub ); - } else { - sub = hb_fifo_get( subtitle->fifo_raw ); - hb_fifo_push( subtitle->fifo_out, sub ); - } - } - } - /* Push the frame to the renderer */ hb_fifo_push( job->fifo_sync, buf_tmp ); diff --git a/libhb/work.c b/libhb/work.c index 7b270ca70..59dea5dfe 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -501,16 +501,16 @@ static void do_job( hb_job_t * job, int cpu_count ) * * select_subtitle implies that we did a scan. */ - if( !job->indepth_scan && job->subtitle_force && + if( !job->indepth_scan && subtitle->force && job->select_subtitle ) { if( subtitle->forced_hits == 0 ) { - job->subtitle_force = 0; + subtitle->force = 0; } } - if( (!job->indepth_scan || job->subtitle_force) && + if( (!job->indepth_scan || subtitle->force) && subtitle->source == VOBSUB ) { /* * Don't add threads for subtitles when we are scanning, unless @@ -519,6 +519,7 @@ static void do_job( hb_job_t * job, int cpu_count ) w = hb_get_work( WORK_DECVOBSUB ); w->fifo_in = subtitle->fifo_in; w->fifo_out = subtitle->fifo_raw; + w->subtitle = subtitle; hb_list_add( job->list_work, w ); } @@ -541,6 +542,7 @@ static void do_job( hb_job_t * job, int cpu_count ) w = hb_get_work( WORK_ENCVOBSUB ); w->fifo_in = subtitle->fifo_sync; w->fifo_out = subtitle->fifo_out; + w->subtitle = subtitle; hb_list_add( job->list_work, w ); } } diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 85431646d..250c8fef8 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -2615,10 +2615,6 @@ fWorkingCount = 0; job->file = [[queueToApply objectForKey:@"DestinationPath"] UTF8String]; //[self writeToActivityLog: "processNewQueueEncode sending to prepareJob"]; [self prepareJob]; - if( [[queueToApply objectForKey:@"SubtitlesForced"] intValue] == 1 ) - job->subtitle_force = 1; - else - job->subtitle_force = 0; /* * If scanning we need to do some extra setup of the job. @@ -3217,6 +3213,10 @@ fWorkingCount = 0; job->indepth_scan = 0; hb_subtitle_t *subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, [[queueToApply objectForKey:@"JobSubtitlesIndex"] intValue] - 2 ); + if( [[queueToApply objectForKey:@"SubtitlesForced"] intValue] == 1 ) + subtitle->force = 1; + else + subtitle->force = 0; hb_list_add( job->list_subtitle, subtitle ); break; } diff --git a/test/test.c b/test/test.c index 3fecfb1cc..44e44d14f 100644 --- a/test/test.c +++ b/test/test.c @@ -1655,6 +1655,9 @@ static int HandleEvents( hb_handle_t * h ) */ subtitle = hb_list_item( title->list_subtitle, sub-1 ); if( subtitle ) { + if( subtitle_force ) { + subtitle->force = subtitle_force; + } hb_list_add( job->list_subtitle, subtitle ); } else { fprintf( stderr, "Could not find subtitle track %d, skipped\n", sub ); @@ -1709,11 +1712,6 @@ static int HandleEvents( hb_handle_t * h ) if (maxHeight) job->maxHeight = maxHeight; - if( subtitle_force ) - { - job->subtitle_force = subtitle_force; - } - if( start_at_preview ) { job->start_at_preview = start_at_preview - 1; |