summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/libmkv/module.defs3
-rw-r--r--gtk/src/Makefile.am2
-rw-r--r--gtk/src/callbacks.c10
-rw-r--r--gtk/src/ghb.ui178
-rw-r--r--gtk/src/hb-backend.c472
-rw-r--r--gtk/src/hb-backend.h19
-rw-r--r--gtk/src/internal_defaults.xml18
-rw-r--r--gtk/src/main.c64
-rw-r--r--gtk/src/presets.c139
-rw-r--r--gtk/src/queuehandler.c4
-rw-r--r--gtk/src/settings.c6
-rw-r--r--gtk/src/settings.h1
-rw-r--r--libhb/common.h5
-rw-r--r--libhb/decvobsub.c102
-rw-r--r--libhb/dvdnav.c4
-rw-r--r--libhb/encvobsub.c18
-rw-r--r--libhb/fifo.c1
-rw-r--r--libhb/muxmkv.c87
-rw-r--r--libhb/reader.c2
-rw-r--r--libhb/sync.c246
-rw-r--r--libhb/work.c8
-rw-r--r--macosx/Controller.mm8
-rw-r--r--test/test.c8
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">&lt;b&gt;Preferred Audio Language&lt;/b&gt;</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">&lt;b&gt;Subtitles&lt;/b&gt;</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">&lt;b&gt;Storage&lt;/b&gt;</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;