summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/ffmpeg/A09-pgs-pts.patch82
-rw-r--r--gtk/src/callbacks.c1
-rw-r--r--gtk/src/hb-backend.c53
-rw-r--r--gtk/src/hb-backend.h1
-rw-r--r--gtk/src/subtitlehandler.c126
-rw-r--r--gtk/src/subtitlehandler.h4
-rw-r--r--libhb/bd.c58
-rw-r--r--libhb/common.c59
-rw-r--r--libhb/common.h14
-rw-r--r--libhb/cropscale.c1
-rw-r--r--libhb/deblock.c1
-rw-r--r--libhb/deccc608sub.c2
-rw-r--r--libhb/decdca.c3
-rw-r--r--libhb/decmpeg2.c3
-rw-r--r--libhb/decomb.c1
-rw-r--r--libhb/decpgssub.c268
-rw-r--r--libhb/decvobsub.c22
-rw-r--r--libhb/deinterlace.c1
-rw-r--r--libhb/denoise.c1
-rw-r--r--libhb/detelecine.c1
-rw-r--r--libhb/dvd.c4
-rw-r--r--libhb/dvdnav.c4
-rw-r--r--libhb/encavcodec.c1
-rw-r--r--libhb/hb.c4
-rw-r--r--libhb/hb_dict.c3
-rw-r--r--libhb/internal.h3
-rw-r--r--libhb/muxmkv.c28
-rw-r--r--libhb/ports.c2
-rw-r--r--libhb/rendersub.c150
-rw-r--r--libhb/rotate.c1
-rw-r--r--libhb/scan.c2
-rw-r--r--libhb/stream.c209
-rw-r--r--libhb/sync.c4
-rw-r--r--libhb/vfr.c1
-rw-r--r--libhb/work.c306
-rw-r--r--macosx/Controller.m115
-rw-r--r--macosx/HBSubtitles.m20
-rw-r--r--test/test.c7
38 files changed, 1236 insertions, 330 deletions
diff --git a/contrib/ffmpeg/A09-pgs-pts.patch b/contrib/ffmpeg/A09-pgs-pts.patch
new file mode 100644
index 000000000..b03f5acce
--- /dev/null
+++ b/contrib/ffmpeg/A09-pgs-pts.patch
@@ -0,0 +1,82 @@
+diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/avcodec.h ffmpeg-v0.7-1696-gcae4f4b/libavcodec/avcodec.h
+--- ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/avcodec.h 2011-11-03 12:29:48.000000000 +0100
++++ ffmpeg-v0.7-1696-gcae4f4b/libavcodec/avcodec.h 2012-04-22 10:59:41.122351884 +0200
+@@ -3193,6 +3193,7 @@
+ unsigned num_rects;
+ AVSubtitleRect **rects;
+ int64_t pts; ///< Same as packet pts, in AV_TIME_BASE
++ uint8_t forced;
+ } AVSubtitle;
+
+ /* packet functions */
+diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-1696-gcae4f4b/libavcodec/pgssubdec.c
+--- ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c 2011-11-03 12:29:48.000000000 +0100
++++ ffmpeg-v0.7-1696-gcae4f4b/libavcodec/pgssubdec.c 2012-04-22 13:09:29.499671541 +0200
+@@ -45,6 +45,8 @@
+ int y;
+ int id_number;
+ int object_number;
++ uint8_t composition_flag;
++ int64_t pts;
+ } PGSSubPresentation;
+
+ typedef struct PGSSubPicture {
+@@ -271,7 +273,8 @@
+ * @todo TODO: Implement forcing of subtitles
+ */
+ static void parse_presentation_segment(AVCodecContext *avctx,
+- const uint8_t *buf, int buf_size)
++ const uint8_t *buf, int buf_size,
++ int64_t pts)
+ {
+ PGSSubContext *ctx = avctx->priv_data;
+
+@@ -280,6 +283,8 @@
+ int w = bytestream_get_be16(&buf);
+ int h = bytestream_get_be16(&buf);
+
++ ctx->presentation.pts = pts;
++
+ av_dlog(avctx, "Video Dimensions %dx%d\n",
+ w, h);
+ if (av_image_check_size(w, h, 0, avctx) >= 0)
+@@ -299,16 +304,17 @@
+ buf += 3;
+
+ ctx->presentation.object_number = bytestream_get_byte(&buf);
++ ctx->presentation.composition_flag = 0;
+ if (!ctx->presentation.object_number)
+ return;
+
+ /*
+- * Skip 4 bytes of unknown:
++ * Skip 3 bytes of unknown:
+ * object_id_ref (2 bytes),
+ * window_id_ref,
+- * composition_flag (0x80 - object cropped, 0x40 - object forced)
+ */
+- buf += 4;
++ buf += 3;
++ ctx->presentation.composition_flag = bytestream_get_byte(&buf);
+
+ x = bytestream_get_be16(&buf);
+ y = bytestream_get_be16(&buf);
+@@ -356,6 +362,9 @@
+ */
+
+ memset(sub, 0, sizeof(*sub));
++ sub->pts = ctx->presentation.pts;
++ sub->forced = (ctx->presentation.composition_flag & 0x40) != 0;
++
+ // Blank if last object_number was 0.
+ // Note that this may be wrong for more complex subtitles.
+ if (!ctx->presentation.object_number)
+@@ -441,7 +450,7 @@
+ parse_picture_segment(avctx, buf, segment_length);
+ break;
+ case PRESENTATION_SEGMENT:
+- parse_presentation_segment(avctx, buf, segment_length);
++ parse_presentation_segment(avctx, buf, segment_length, avpkt->pts);
+ break;
+ case WINDOW_SEGMENT:
+ /*
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c
index 94a932d67..ba0d569cc 100644
--- a/gtk/src/callbacks.c
+++ b/gtk/src/callbacks.c
@@ -1268,6 +1268,7 @@ container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
ghb_clear_presets_selection(ud);
ghb_live_reset(ud);
ghb_subtitle_prune(ud);
+ ghb_subtitle_list_refresh_selected(ud);
ghb_audio_list_refresh_selected(ud);
}
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index 2b2b66348..af1b890e5 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -1423,37 +1423,6 @@ ghb_subtitle_track_source(GValue *settings, gint track)
}
const char*
-ghb_subtitle_source_name(gint source)
-{
- const gchar * name = "Unknown";
- switch (source)
- {
- case VOBSUB:
- name = "VOBSUB";
- break;
- case TX3GSUB:
- name = "TX3G";
- break;
- case UTF8SUB:
- name = "UTF8";
- break;
- case CC708SUB:
- case CC608SUB:
- name = "CC";
- break;
- case SRTSUB:
- name = "SRT";
- break;
- case SSASUB:
- name = "SSA";
- break;
- default:
- break;
- }
- return name;
-}
-
-const char*
ghb_subtitle_track_source_name(GValue *settings, gint track)
{
gint titleindex;
@@ -1491,7 +1460,7 @@ ghb_subtitle_track_source_name(GValue *settings, gint track)
sub = hb_list_item( title->list_subtitle, track);
if (sub != NULL)
{
- name = ghb_subtitle_source_name(sub->source);
+ name = hb_subsource_name(sub->source);
}
done:
@@ -2304,7 +2273,7 @@ subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
options[ii] = g_strdup_printf("%d - %s (%s)", ii+1,
subtitle->lang,
- ghb_subtitle_source_name(subtitle->source));
+ hb_subsource_name(subtitle->source));
subtitle_opts.map[ii+1].option = options[ii];
subtitle_opts.map[ii+1].shortOpt = index_str[ii];
subtitle_opts.map[ii+1].ivalue = ii;
@@ -2681,18 +2650,6 @@ ghb_find_cc_track(gint titleindex)
return -2;
}
-static gboolean
-canForce(int source)
-{
- return (source == VOBSUB);
-}
-
-static gboolean
-canBurn(int source)
-{
- return (source == VOBSUB || source == SSASUB);
-}
-
gint
ghb_find_subtitle_track(
gint titleindex,
@@ -2745,8 +2702,8 @@ ghb_find_subtitle_track(
continue;
subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
- if (((!force || (force && canForce(subtitle->source))) &&
- (!burn || (burn && canBurn(subtitle->source)))) &&
+ if (((!force || (force && ghb_canForceSub(subtitle->source))) &&
+ (!burn || (burn && ghb_canBurnSub(subtitle->source)))) &&
((strcmp(lang, subtitle->iso639_2) == 0) ||
(strcmp(lang, "und") == 0)))
{
@@ -5106,7 +5063,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
{
sub_config.dest = PASSTHRUSUB;
}
- else if ( burned && canBurn(subt->source) )
+ else if ( burned && ghb_canBurnSub(subt->source) )
{
// Only allow one subtitle to be burned into the video
if (one_burned)
diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h
index 407dc7315..22f3f6770 100644
--- a/gtk/src/hb-backend.h
+++ b/gtk/src/hb-backend.h
@@ -163,7 +163,6 @@ gint ghb_get_title_number(gint titleindex);
int ghb_get_title_count();
gint ghb_subtitle_track_source(GValue *settings, gint track);
const char* ghb_subtitle_track_source_name(GValue *settings, gint track);
-const char* ghb_subtitle_source_name(gint source);
gchar* ghb_subtitle_track_lang(GValue *settings, gint track);
gboolean ghb_validate_vquality(GValue *settings);
diff --git a/gtk/src/subtitlehandler.c b/gtk/src/subtitlehandler.c
index ffe38a0e6..5b5036520 100644
--- a/gtk/src/subtitlehandler.c
+++ b/gtk/src/subtitlehandler.c
@@ -42,16 +42,22 @@ free_subtitle_key(gpointer data)
g_free(data);
}
-static gboolean
-canBurn(int source)
+gboolean
+ghb_canPassSub(int source, int mux)
{
- return (source == VOBSUB || source == SSASUB);
+ return hb_subtitle_can_pass(source, mux);
}
-static gboolean
-canForce(int source)
+gboolean
+ghb_canBurnSub(int source)
{
- return (source == VOBSUB);
+ return hb_subtitle_can_burn(source);
+}
+
+gboolean
+ghb_canForceSub(int source)
+{
+ return hb_subtitle_can_force(source);
}
gboolean
@@ -86,7 +92,6 @@ ghb_subtitle_exclusive_burn_settings(GValue *settings, gint index)
{
if (ii != index)
{
-printf("settings burn %d also %d\n", index, ii);
subsettings = ghb_array_get_nth(subtitle_list, ii);
ghb_settings_set_boolean(subsettings, "SubtitleBurned", FALSE);
}
@@ -114,7 +119,6 @@ ghb_subtitle_exclusive_burn(signal_user_data_t *ud, gint index)
gtk_tree_model_iter_nth_child(tm, &ti, NULL, ii);
if (ii != index)
{
-printf("ui burn %d also %d\n", index, ii);
subsettings = ghb_array_get_nth(subtitle_list, ii);
ghb_settings_set_boolean(subsettings, "SubtitleBurned", FALSE);
gtk_list_store_set(GTK_LIST_STORE(tm), &ti, 2, FALSE, -1);
@@ -226,7 +230,8 @@ ghb_add_subtitle_to_settings(GValue *settings, GValue *subsettings)
// Add the current subtitle settings to the list.
GValue *subtitle_list;
gint count;
- gboolean burned;
+ gboolean burned, forced;
+ gint source, mux;
const gchar *track;
const gchar *lang;
@@ -256,9 +261,29 @@ ghb_add_subtitle_to_settings(GValue *settings, GValue *subsettings)
lang = ghb_settings_combo_string(subsettings, "SubtitleTrack");
ghb_settings_set_string(subsettings, "SubtitleLanguage", lang);
+ mux = ghb_settings_combo_int(settings, "FileFormat");
+ source = ghb_settings_get_int(subsettings, "SubtitleSource");
+ burned = ghb_settings_get_boolean(subsettings, "SubtitleBurned");
+ if (burned && !ghb_canBurnSub(source))
+ {
+ burned = FALSE;
+ ghb_settings_set_boolean(subsettings, "SubtitleBurned", burned);
+ }
+ if (!burned && !ghb_canPassSub(source, mux))
+ {
+ burned = TRUE;
+ ghb_settings_set_boolean(subsettings, "SubtitleBurned", burned);
+ ghb_settings_set_boolean(subsettings, "SubtitleDefaultTrack", FALSE);
+ }
+ forced = ghb_settings_get_boolean(subsettings, "SubtitleForced");
+ if (forced && !ghb_canForceSub(source))
+ {
+ forced = FALSE;
+ ghb_settings_set_boolean(subsettings, "SubtitleForced", forced);
+ }
+
ghb_array_append(subtitle_list, subsettings);
- burned = ghb_settings_get_boolean(subsettings, "SubtitleBurned");
if (burned)
ghb_subtitle_exclusive_burn_settings(settings, count);
return TRUE;
@@ -300,6 +325,7 @@ add_all_pref_subtitles(signal_user_data_t *ud)
for (ii = 0; ii < count; ii++)
{
subtitle = ghb_value_dup(ghb_array_get_nth(pref_subtitle, ii));
+ gboolean force = ghb_settings_get_boolean(subtitle, "SubtitleForced");
lang = ghb_settings_get_string(subtitle, "SubtitleLanguage");
// If there are multiple subtitles using the same language, then
// select sequential tracks for each. The hash keeps track
@@ -417,7 +443,7 @@ ghb_set_pref_subtitle_settings(gint titleindex, GValue *settings)
GValue *subsettings;
gboolean burn;
- track = ghb_find_subtitle_track(titleindex, pref_lang, FALSE, FALSE, VOBSUB, track_indices);
+ track = ghb_find_subtitle_track(titleindex, pref_lang, FALSE, FALSE, PGSSUB, track_indices);
if (track >= -1)
{
int source;
@@ -463,7 +489,6 @@ ghb_set_pref_subtitle_settings(gint titleindex, GValue *settings)
if (track >= 0)
{
int source;
-
subsettings = ghb_dict_value_new();
ghb_settings_set_int(subsettings, "SubtitleTrack", track);
source = ghb_subtitle_track_source(settings, track);
@@ -606,8 +631,10 @@ subtitle_forced_toggled_cb(
settings = ghb_array_get_nth(subtitle_list, row);
source = ghb_settings_get_int(settings, "SubtitleSource");
- if (!canForce(source))
+ if (!ghb_canForceSub(source))
+ {
return;
+ }
ghb_settings_set_boolean(settings, "SubtitleForced", active);
gtk_list_store_set(GTK_LIST_STORE(tm), &ti, 1, active, -1);
@@ -630,7 +657,7 @@ subtitle_burned_toggled_cb(
GValue *subtitle_list;
gint count;
GValue *settings;
- gint source;
+ gint source, mux;
g_debug("burned toggled");
tp = gtk_tree_path_new_from_string (path);
@@ -654,7 +681,10 @@ subtitle_burned_toggled_cb(
settings = ghb_array_get_nth(subtitle_list, row);
source = ghb_settings_get_int(settings, "SubtitleSource");
- if (!canBurn(source))
+ if (!ghb_canBurnSub(source))
+ return;
+ mux = ghb_settings_combo_int(ud->settings, "FileFormat");
+ if (!active && !hb_subtitle_can_pass(source, mux))
return;
ghb_settings_set_boolean(settings, "SubtitleBurned", active);
@@ -711,6 +741,12 @@ subtitle_default_toggled_cb(
settings = ghb_array_get_nth(subtitle_list, row);
+ int source, mux;
+ source = ghb_settings_get_int(settings, "SubtitleSource");
+ mux = ghb_settings_combo_int(ud->settings, "FileFormat");
+ if (active && !hb_subtitle_can_pass(source, mux))
+ return;
+
ghb_settings_set_boolean(settings, "SubtitleDefaultTrack", active);
gtk_list_store_set(GTK_LIST_STORE(tm), &ti, 3, active, -1);
@@ -724,8 +760,8 @@ subtitle_default_toggled_cb(
ghb_live_reset(ud);
}
-static void
-subtitle_list_refresh_selected(signal_user_data_t *ud)
+void
+ghb_subtitle_list_refresh_selected(signal_user_data_t *ud)
{
GtkTreeView *treeview;
GtkTreePath *treepath;
@@ -760,22 +796,34 @@ subtitle_list_refresh_selected(signal_user_data_t *ud)
return;
settings = ghb_array_get_nth(subtitle_list, row);
- def = ghb_settings_get_boolean(settings, "SubtitleDefaultTrack");
+ burned = ghb_settings_get_boolean(settings, "SubtitleBurned");
gint i_source;
i_source = ghb_settings_get_int(settings, "SubtitleSource");
- if (!canBurn(i_source))
+ if (!ghb_canBurnSub(i_source))
{
burned = FALSE;
ghb_settings_set_boolean(settings, "SubtitleBurned", burned);
}
- if (!canForce(i_source))
+
+ gint i_mux;
+ i_mux = ghb_settings_combo_int(ud->settings, "FileFormat");
+ if (!burned && !ghb_canPassSub(i_source, i_mux))
+ {
+ burned = TRUE;
+ ghb_settings_set_boolean(settings, "SubtitleBurned", burned);
+ ghb_settings_set_boolean(settings, "SubtitleDefaultTrack", FALSE);
+ }
+
+ forced = ghb_settings_get_boolean(settings, "SubtitleForced");
+ if (!ghb_canForceSub(i_source))
{
- // Force only apply to VOBSUBS
forced = FALSE;
ghb_settings_set_boolean(settings, "SubtitleForced", forced);
}
+ def = ghb_settings_get_boolean(settings, "SubtitleDefaultTrack");
+
if (i_source == SRTSUB)
{
const gchar *lang;
@@ -801,24 +849,18 @@ subtitle_list_refresh_selected(signal_user_data_t *ud)
}
g_free(code);
offset = ghb_settings_get_int(settings, "SrtOffset");
-
- forced = FALSE;
- burned = FALSE;
}
else
{
track = g_strdup(
ghb_settings_combo_option(settings, "SubtitleTrack"));
- source = g_strdup(ghb_subtitle_source_name(i_source));
+ source = g_strdup(hb_subsource_name(i_source));
s_track = ghb_settings_get_string(settings, "SubtitleTrack");
-
- forced = ghb_settings_get_boolean(settings, "SubtitleForced");
- burned = ghb_settings_get_boolean(settings, "SubtitleBurned");
}
- if (canBurn(i_source))
+ if (ghb_canBurnSub(i_source))
allow_burn = TRUE;
- if (canForce(i_source))
+ if (ghb_canForceSub(i_source))
allow_force = TRUE;
gtk_list_store_set(GTK_LIST_STORE(store), &iter,
@@ -864,7 +906,7 @@ subtitle_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
ghb_settings_set_int(settings, "SubtitleSource", source);
lang = ghb_settings_combo_string(settings, "SubtitleTrack");
ghb_settings_set_string(settings, "SubtitleLanguage", lang);
- subtitle_list_refresh_selected(ud);
+ ghb_subtitle_list_refresh_selected(ud);
ghb_live_reset(ud);
}
ghb_live_reset(ud);
@@ -882,7 +924,7 @@ srt_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
if (settings != NULL)
{
ghb_widget_to_setting(settings, widget);
- subtitle_list_refresh_selected(ud);
+ ghb_subtitle_list_refresh_selected(ud);
ghb_live_reset(ud);
}
@@ -902,7 +944,7 @@ srt_file_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
gchar *filename, *dirname;
ghb_widget_to_setting(settings, widget);
- subtitle_list_refresh_selected(ud);
+ ghb_subtitle_list_refresh_selected(ud);
ghb_live_reset(ud);
@@ -936,7 +978,7 @@ srt_lang_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
const gchar *lang;
ghb_widget_to_setting(settings, widget);
- subtitle_list_refresh_selected(ud);
+ ghb_subtitle_list_refresh_selected(ud);
ghb_live_reset(ud);
@@ -982,7 +1024,7 @@ add_to_subtitle_list(
GtkTreeIter iter;
GtkListStore *store;
GtkTreeSelection *selection;
- const gchar *track, *source;
+ const gchar *track;
gboolean forced, burned, def;
gchar *s_track;
gint i_source;
@@ -1001,11 +1043,10 @@ add_to_subtitle_list(
s_track = ghb_settings_get_string(settings, "SubtitleTrack");
i_source = ghb_settings_get_int(settings, "SubtitleSource");
- source = ghb_subtitle_source_name(i_source);
- if (canBurn(i_source))
+ if (ghb_canBurnSub(i_source))
allow_burn = TRUE;
- if (canForce(i_source))
+ if (ghb_canForceSub(i_source))
allow_force = TRUE;
gtk_list_store_append(store, &iter);
@@ -1251,7 +1292,7 @@ subtitle_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
// Add the current subtitle settings to the list.
GValue *settings;
gboolean burned = FALSE;
- gint track, source;
+ gint track, source, mux;
g_debug("subtitle_add_clicked_cb ()");
@@ -1260,6 +1301,11 @@ subtitle_add_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
settings = ghb_dict_value_new();
ghb_settings_set_int(settings, "SubtitleTrack", track);
source = ghb_subtitle_track_source(ud->settings, track);
+
+ // Initialize to passthru if possible, else burn
+ mux = ghb_settings_combo_int(ud->settings, "FileFormat");
+ burned = !hb_subtitle_can_pass(source, mux);
+
ghb_settings_set_int(settings, "SubtitleSource", source);
ghb_settings_take_value(settings, "SubtitleForced",
ghb_boolean_value_new(FALSE));
@@ -1331,7 +1377,6 @@ void
ghb_subtitle_prune(signal_user_data_t *ud)
{
GtkTreeView *tv;
- GtkTreeModel *tm;
GValue *subtitle_list;
gint count, ii;
gint first_track = 0, one_burned = 0;
@@ -1343,7 +1388,6 @@ ghb_subtitle_prune(signal_user_data_t *ud)
tv = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_list"));
g_return_if_fail(tv != NULL);
- tm = gtk_tree_view_get_model(tv);
for (ii = count-1; ii >= 0; ii--)
{
gboolean burned;
diff --git a/gtk/src/subtitlehandler.h b/gtk/src/subtitlehandler.h
index ac662499f..267b79bc2 100644
--- a/gtk/src/subtitlehandler.h
+++ b/gtk/src/subtitlehandler.h
@@ -35,5 +35,9 @@ gint ghb_selected_subtitle_row(signal_user_data_t *ud);
void ghb_reset_subtitles(signal_user_data_t *ud, GValue *settings);
void ghb_subtitle_prune(signal_user_data_t *ud);
gboolean ghb_soft_in_subtitle_list(GValue *subtitle_list);
+gboolean ghb_canBurnSub(int source);
+gboolean ghb_canForceSub(int source);
+gboolean ghb_canPassSub(int source, int mux);
+void ghb_subtitle_list_refresh_selected(signal_user_data_t *ud);
#endif // _SUBTITLEHANDLER_H_
diff --git a/libhb/bd.c b/libhb/bd.c
index 9ec4c078a..bb051115a 100644
--- a/libhb/bd.c
+++ b/libhb/bd.c
@@ -81,6 +81,44 @@ int hb_bd_title_count( hb_bd_t * d )
return d->title_count;
}
+static void add_subtitle(int track, hb_list_t *list_subtitle, BLURAY_STREAM_INFO *bdsub, uint32_t codec)
+{
+ hb_subtitle_t * subtitle;
+ iso639_lang_t * lang;
+
+ subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
+
+ subtitle->track = track;
+ subtitle->id = bdsub->pid;
+ lang = lang_for_code2( (char*)bdsub->lang );
+ 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);
+
+ switch ( bdsub->coding_type )
+ {
+ case BLURAY_STREAM_TYPE_SUB_PG:
+ subtitle->source = PGSSUB;
+ subtitle->format = PICTURESUB;
+ subtitle->config.dest = RENDERSUB;
+ break;
+ default:
+ // Unrecognized, don't add to list
+ free( subtitle );
+ return;
+ }
+ subtitle->reg_desc = STR4_TO_UINT32("HDMV");
+ subtitle->stream_type = bdsub->coding_type;
+ subtitle->codec = codec;
+
+ hb_log( "bd: subtitle id=0x%x, lang=%s, 3cc=%s", subtitle->id,
+ subtitle->lang, subtitle->iso639_2 );
+
+ hb_list_add( list_subtitle, subtitle );
+ return;
+}
+
static void add_audio(int track, hb_list_t *list_audio, BLURAY_STREAM_INFO *bdaudio, int substream_type, uint32_t codec, uint32_t codec_param)
{
hb_audio_t * audio;
@@ -89,6 +127,7 @@ static void add_audio(int track, hb_list_t *list_audio, BLURAY_STREAM_INFO *bdau
audio = calloc( sizeof( hb_audio_t ), 1 );
audio->id = (substream_type << 16) | bdaudio->pid;
+ audio->config.in.reg_desc = STR4_TO_UINT32("HDMV");
audio->config.in.stream_type = bdaudio->coding_type;
audio->config.in.substream_type = substream_type;
audio->config.in.codec = codec;
@@ -393,6 +432,25 @@ hb_title_t * hb_bd_title_scan( hb_bd_t * d, int tt, uint64_t min_duration )
}
}
+ // Add all the subtitles found in the above clip.
+ for ( ii = 0; ii < ti->clips[audio_clip_index].pg_stream_count; ii++ )
+ {
+ BLURAY_STREAM_INFO * bdpgs;
+
+ bdpgs = &ti->clips[audio_clip_index].pg_streams[ii];
+
+ switch( bdpgs->coding_type )
+ {
+ case BLURAY_STREAM_TYPE_SUB_PG:
+ add_subtitle(ii, title->list_subtitle, bdpgs, WORK_DECPGSSUB);
+ break;
+ default:
+ hb_log( "scan: unknown subtitle pid 0x%x codec 0x%x",
+ bdpgs->pid, bdpgs->coding_type );
+ break;
+ }
+ }
+
/* Chapters */
for ( ii = 0; ii < ti->chapter_count; ii++ )
{
diff --git a/libhb/common.c b/libhb/common.c
index 3f3097485..23c6ea21e 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -1751,6 +1751,7 @@ int hb_subtitle_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlec
return 0;
}
subtitle->config = *subtitlecfg;
+ subtitle->out_track = hb_list_count(job->list_subtitle) + 1;
hb_list_add(job->list_subtitle, subtitle);
return 1;
}
@@ -1768,6 +1769,7 @@ int hb_srt_add( const hb_job_t * job,
subtitle->id = (hb_list_count(job->list_subtitle) << 8) | 0xFF;
subtitle->format = TEXTSUB;
subtitle->source = SRTSUB;
+ subtitle->codec = WORK_DECSRTSUB;
language = lang_for_code2( lang );
@@ -1786,6 +1788,61 @@ int hb_srt_add( const hb_job_t * job,
return retval;
}
+int hb_subtitle_can_force( int source )
+{
+ return source == VOBSUB || source == PGSSUB;
+}
+
+int hb_subtitle_can_burn( int source )
+{
+ return source == VOBSUB || source == PGSSUB || source == SSASUB;
+}
+
+int hb_subtitle_can_pass( int source, int mux )
+{
+ if ( mux == HB_MUX_MKV )
+ {
+ switch( source )
+ {
+ case PGSSUB:
+ case VOBSUB:
+ case SSASUB:
+ case SRTSUB:
+ case UTF8SUB:
+ case TX3GSUB:
+ case CC608SUB:
+ case CC708SUB:
+ return 1;
+
+ default:
+ return 0;
+ }
+ }
+ else if ( mux == HB_MUX_MP4 )
+ {
+ switch( source )
+ {
+ case VOBSUB:
+ case SSASUB:
+ case SRTSUB:
+ case UTF8SUB:
+ case TX3GSUB:
+ case CC608SUB:
+ case CC708SUB:
+ return 1;
+
+ default:
+ return 0;
+ }
+ }
+ else
+ {
+ // Internal error. Should never get here.
+ hb_error("internel error. Bad mux %d\n", mux);
+ return 0;
+ }
+}
+
char * hb_strdup_printf( const char * fmt, ... )
{
int len;
@@ -1964,6 +2021,8 @@ const char * hb_subsource_name( int source )
return "TX3G";
case SSASUB:
return "SSA";
+ case PGSSUB:
+ return "PGS";
default:
return "Unknown";
}
diff --git a/libhb/common.h b/libhb/common.h
index d38f77a0b..741c32e03 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -122,6 +122,9 @@ hb_subtitle_t *hb_subtitle_copy(const hb_subtitle_t *src);
int hb_subtitle_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlecfg, int track);
int hb_srt_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlecfg,
const char *lang);
+int hb_subtitle_can_force( int source );
+int hb_subtitle_can_burn( int source );
+int hb_subtitle_can_pass( int source, int mux );
hb_attachment_t *hb_attachment_copy(const hb_attachment_t *src);
@@ -610,11 +613,12 @@ struct hb_subtitle_s
{
int id;
int track;
+ int out_track;
hb_subtitle_config_t config;
enum subtype { PICTURESUB, TEXTSUB } format;
- enum subsource { VOBSUB, SRTSUB, CC608SUB, /*unused*/CC708SUB, UTF8SUB, TX3GSUB, SSASUB } source;
+ enum subsource { VOBSUB, SRTSUB, CC608SUB, /*unused*/CC708SUB, UTF8SUB, TX3GSUB, SSASUB, PGSSUB } source;
char lang[1024];
char iso639_2[4];
uint8_t type; /* Closed Caption, Childrens, Directors etc */
@@ -622,6 +626,7 @@ struct hb_subtitle_s
// Color lookup table for VOB subtitle tracks. Each entry is in YCbCr format.
// Must be filled out by the demuxer for VOB subtitle tracks.
uint32_t palette[16];
+ uint8_t palette_set;
int width;
int height;
@@ -634,6 +639,11 @@ struct hb_subtitle_s
#ifdef __LIBHB__
/* Internal data */
+ PRIVATE uint32_t codec; /* Input "codec" */
+ PRIVATE uint32_t reg_desc; /* registration descriptor of source */
+ PRIVATE uint32_t stream_type; /* stream type from source stream */
+ PRIVATE uint32_t substream_type;/* substream for multiplexed streams */
+
hb_fifo_t * fifo_in; /* SPU ES */
hb_fifo_t * fifo_raw; /* Decoded SPU */
hb_fifo_t * fifo_sync;/* Synced */
@@ -873,6 +883,7 @@ extern hb_work_object_t hb_decsrtsub;
extern hb_work_object_t hb_decutf8sub;
extern hb_work_object_t hb_dectx3gsub;
extern hb_work_object_t hb_decssasub;
+extern hb_work_object_t hb_decpgssub;
extern hb_work_object_t hb_encavcodec;
extern hb_work_object_t hb_encx264;
extern hb_work_object_t hb_enctheora;
@@ -920,6 +931,7 @@ struct hb_filter_object_s
{
int id;
int enforce_order;
+ int init_index;
char * name;
char * settings;
diff --git a/libhb/cropscale.c b/libhb/cropscale.c
index 11a22a44e..c11e931ee 100644
--- a/libhb/cropscale.c
+++ b/libhb/cropscale.c
@@ -30,6 +30,7 @@ hb_filter_object_t hb_filter_crop_scale =
{
.id = HB_FILTER_CROP_SCALE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Crop and Scale",
.settings = NULL,
.init = hb_crop_scale_init,
diff --git a/libhb/deblock.c b/libhb/deblock.c
index dab622abc..6d1f1aaec 100644
--- a/libhb/deblock.c
+++ b/libhb/deblock.c
@@ -63,6 +63,7 @@ hb_filter_object_t hb_filter_deblock =
{
.id = HB_FILTER_DEBLOCK,
.enforce_order = 1,
+ .init_index = 0,
.name = "Deblock (pp7)",
.settings = NULL,
.init = hb_deblock_init,
diff --git a/libhb/deccc608sub.c b/libhb/deccc608sub.c
index aaa3d020d..1d16410e4 100644
--- a/libhb/deccc608sub.c
+++ b/libhb/deccc608sub.c
@@ -1607,7 +1607,7 @@ int write_cc_buffer_as_srt (struct eia608_screen *data, struct s_write *wb)
if (debug_608)
{
hb_log ("\n- - - SRT caption - - -\n");
- hb_log (timeline);
+ hb_log ("%s", timeline);
}
//fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
diff --git a/libhb/decdca.c b/libhb/decdca.c
index 1e6e4192c..5bc118007 100644
--- a/libhb/decdca.c
+++ b/libhb/decdca.c
@@ -157,7 +157,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
hb_buffer_t * buf;
hb_audio_t * audio = w->audio;
int i, j, k;
- int64_t pts, pos;
+ int64_t pts;
uint64_t upts, upos;
int num_blocks;
@@ -203,7 +203,6 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
/* Get the whole frame */
hb_list_getbytes( pv->list, pv->frame, pv->size, &upts, &upos );
pts = (int64_t)upts;
- pos = (int64_t)upos;
if ( pts != pv->last_buf_pts )
{
diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c
index 82ba78e31..95b189af0 100644
--- a/libhb/decmpeg2.c
+++ b/libhb/decmpeg2.c
@@ -654,6 +654,7 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
subtitle->format = TEXTSUB;
subtitle->source = CC608SUB;
subtitle->config.dest = PASSTHRUSUB;
+ subtitle->codec = WORK_DECCC608;
subtitle->type = 5;
snprintf( subtitle->lang, sizeof( subtitle->lang ), "Closed Captions");
/*
@@ -664,7 +665,7 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
if( audio )
{
snprintf( subtitle->iso639_2, sizeof( subtitle->iso639_2 ),
- audio->config.lang.iso639_2);
+ "%s", audio->config.lang.iso639_2);
} else {
snprintf( subtitle->iso639_2, sizeof( subtitle->iso639_2 ), "und");
}
diff --git a/libhb/decomb.c b/libhb/decomb.c
index 7d911ff28..fae95caea 100644
--- a/libhb/decomb.c
+++ b/libhb/decomb.c
@@ -233,6 +233,7 @@ hb_filter_object_t hb_filter_decomb =
{
.id = HB_FILTER_DECOMB,
.enforce_order = 1,
+ .init_index = 0,
.name = "Decomb",
.settings = NULL,
.init = hb_decomb_init,
diff --git a/libhb/decpgssub.c b/libhb/decpgssub.c
new file mode 100644
index 000000000..1b0f7e4cd
--- /dev/null
+++ b/libhb/decpgssub.c
@@ -0,0 +1,268 @@
+#include "hb.h"
+#include "hbffmpeg.h"
+
+struct hb_work_private_s
+{
+ AVCodecContext * context;
+ hb_job_t * job;
+ // For PGS subs, when doing passthru, we don't know if we need a
+ // packet until we have processed several packets. So we cache
+ // all the packets we see until libav returns a subtitle with
+ // the information we need.
+ hb_buffer_t * list_pass_buffer;
+ hb_buffer_t * last_pass_buffer;
+ // It is possible for multiple subtitles to be enncapsulated in
+ // one packet. This won't happen for PGS subs, but may for other
+ // types of subtitles. Since I plan to generalize this code to handle
+ // other than PGS, we will need to keep a list of all subtitles seen
+ // while parsing an input packet.
+ hb_buffer_t * list_buffer;
+ hb_buffer_t * last_buffer;
+};
+
+static int decsubInit( hb_work_object_t * w, hb_job_t * job )
+{
+ AVCodec *codec = avcodec_find_decoder( CODEC_ID_HDMV_PGS_SUBTITLE );
+ AVCodecContext *context = avcodec_alloc_context3( codec );
+ context->codec = codec;
+
+ hb_work_private_t * pv;
+ pv = calloc( 1, sizeof( hb_work_private_t ) );
+ w->private_data = pv;
+
+ pv->context = context;
+ pv->job = job;
+
+ return 0;
+}
+
+static int decsubWork( 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 ( in->size <= 0 )
+ {
+ /* EOF on input stream - send it downstream & say that we're done */
+ if ( pv->list_buffer == NULL )
+ {
+ pv->list_buffer = pv->last_buffer = in;
+ }
+ else
+ {
+ pv->last_buffer->next = in;
+ }
+ *buf_in = NULL;
+ *buf_out = pv->list_buffer;
+ pv->list_buffer = NULL;
+
+ return HB_WORK_DONE;
+ }
+
+ if ( !pv->job->indepth_scan &&
+ w->subtitle->config.dest == PASSTHRUSUB &&
+ hb_subtitle_can_pass( PGSSUB, pv->job->mux ) )
+ {
+ // Append to buffer list. It will be sent to fifo after we determine
+ // if this is a packet we need.
+ if ( pv->list_pass_buffer == NULL )
+ {
+ pv->list_pass_buffer = pv->last_pass_buffer = in;
+ }
+ else
+ {
+ pv->last_pass_buffer->next = in;
+ pv->last_pass_buffer = in;
+ }
+ // We are keeping the buffer, so prevent the filter loop from
+ // deleting it.
+ *buf_in = NULL;
+ }
+
+ AVSubtitle subtitle;
+ memset( &subtitle, 0, sizeof(subtitle) );
+
+ AVPacket avp;
+ av_init_packet( &avp );
+ avp.data = in->data;
+ avp.size = in->size;
+ // libav wants pkt pts in AV_TIME_BASE units
+ avp.pts = av_rescale(in->s.start, AV_TIME_BASE, 90000);
+
+ int has_subtitle = 0;
+
+ do
+ {
+ int usedBytes = avcodec_decode_subtitle2( pv->context, &subtitle, &has_subtitle, &avp );
+ if (usedBytes < 0)
+ {
+ hb_log("unable to decode subtitle with %d bytes.", avp.size);
+ return HB_WORK_OK;
+ }
+
+ if (usedBytes <= avp.size)
+ {
+ avp.data += usedBytes;
+ avp.size -= usedBytes;
+ }
+ else
+ {
+ avp.size = 0;
+ }
+
+ // The sub is "usable" if:
+ // 1. libav returned a sub AND
+ // 2. we are scanning for foreign audio subs OR
+ // 3. we want all subs (e.g. not forced) OR
+ // 4. the sub is forced and we only want forced OR
+ // 5. subtitle clears the previous sub (these are never forced)
+ // subtitle.num_rects == 0
+ uint8_t useable_sub =
+ pv->job->indepth_scan ||
+ subtitle.num_rects == 0 ||
+ !w->subtitle->config.force ||
+ ( w->subtitle->config.force && subtitle.forced );
+
+ if (has_subtitle && useable_sub)
+ {
+ int64_t pts = av_rescale(subtitle.pts, 90000, AV_TIME_BASE);
+ hb_buffer_t * out = NULL;
+
+ if( pv->job->indepth_scan )
+ {
+ if (subtitle.forced)
+ {
+ w->subtitle->forced_hits++;
+ }
+ }
+ else if ( w->subtitle->config.dest == PASSTHRUSUB &&
+ hb_subtitle_can_pass( PGSSUB, pv->job->mux ) )
+ {
+ out = pv->list_pass_buffer;
+ pv->list_pass_buffer = NULL;
+ }
+ else
+ {
+ if (subtitle.num_rects != 0)
+ {
+ unsigned ii;
+ for (ii = 0; ii < subtitle.num_rects; ii++)
+ {
+ AVSubtitleRect *rect = subtitle.rects[ii];
+
+ out = hb_frame_buffer_init(
+ PIX_FMT_YUVA420P, rect->w, rect->h );
+
+ out->s.id = in->s.id;
+ out->sequence = in->sequence;
+ out->s.start = pts;
+ out->s.stop = 0;
+ out->f.x = rect->x;
+ out->f.y = rect->y;
+
+ uint8_t *lum = out->plane[0].data;
+ uint8_t *chromaU = out->plane[1].data;
+ uint8_t *chromaV = out->plane[2].data;
+ uint8_t *alpha = out->plane[3].data;
+
+ int xx, yy;
+ for (yy = 0; yy < rect->h; yy++)
+ {
+ for (xx = 0; xx < rect->w; xx++)
+ {
+ uint32_t argb, yuv;
+ int pixel;
+ uint8_t color;
+
+ pixel = yy * rect->w + xx;
+ color = rect->pict.data[0][pixel];
+ argb = ((uint32_t*)rect->pict.data[1])[color];
+ yuv = hb_rgb2yuv(argb);
+
+ lum[xx] = (yuv >> 16) & 0xff;
+ alpha[xx] = (argb >> 24) & 0xff;
+ if ((xx & 1) == 0 && (yy & 1) == 0)
+ {
+ chromaV[xx>>1] = (yuv >> 8) & 0xff;
+ chromaU[xx>>1] = yuv & 0xff;
+ }
+ }
+ lum += out->plane[0].stride;
+ if ((yy & 1) == 0)
+ {
+ chromaU += out->plane[1].stride;
+ chromaV += out->plane[2].stride;
+ }
+ alpha += out->plane[3].stride;
+ }
+
+ if ( pv->list_buffer == NULL )
+ {
+ pv->list_buffer = pv->last_buffer = out;
+ }
+ else
+ {
+ pv->last_buffer->next = out;
+ pv->last_buffer = out;
+ }
+ out = NULL;
+ }
+ }
+ else
+ {
+ out = hb_buffer_init( 1 );
+
+ out->s.id = in->s.id;
+ out->s.start = pts;
+ out->s.stop = 0;
+ out->f.x = 0;
+ out->f.y = 0;
+ out->f.width = 0;
+ out->f.height = 0;
+ }
+ }
+ if ( pv->list_buffer == NULL )
+ {
+ pv->list_buffer = pv->last_buffer = out;
+ }
+ else
+ {
+ pv->last_buffer->next = out;
+ }
+ while (pv->last_buffer && pv->last_buffer->next)
+ {
+ pv->last_buffer = pv->last_buffer->next;
+ }
+ }
+ else if ( has_subtitle )
+ {
+ hb_buffer_close( &pv->list_pass_buffer );
+ pv->list_pass_buffer = NULL;
+ }
+ if ( has_subtitle )
+ {
+ avsubtitle_free(&subtitle);
+ }
+ } while (avp.size > 0);
+
+ *buf_out = pv->list_buffer;
+ pv->list_buffer = NULL;
+ return HB_WORK_OK;
+}
+
+static void decsubClose( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+ avcodec_flush_buffers( pv->context );
+ avcodec_close( pv->context );
+}
+
+hb_work_object_t hb_decpgssub =
+{
+ WORK_DECPGSSUB,
+ "PGS decoder",
+ decsubInit,
+ decsubWork,
+ decsubClose
+};
diff --git a/libhb/decvobsub.c b/libhb/decvobsub.c
index b633e7804..43f2aefd9 100644
--- a/libhb/decvobsub.c
+++ b/libhb/decvobsub.c
@@ -49,6 +49,7 @@ struct hb_work_private_s
uint8_t chromaU[4];
uint8_t chromaV[4];
uint8_t alpha[4];
+ uint8_t palette_set;
};
static hb_buffer_t * Decode( hb_work_object_t * );
@@ -64,18 +65,23 @@ int decsubInit( hb_work_object_t * w, hb_job_t * job )
pv->pts = 0;
// Warn if the input color palette is empty
- int paletteEmpty = 1;
- int i;
- for (i=0; i<16; i++)
+ pv->palette_set = w->subtitle->palette_set;
+ if ( pv->palette_set )
{
- if (w->subtitle->palette[i])
+ // Make sure the entries in the palette are not all 0
+ pv->palette_set = 0;
+ int i;
+ for (i=0; i<16; i++)
{
- paletteEmpty = 0;
- break;
+ if (w->subtitle->palette[i])
+ {
+ pv->palette_set = 1;
+ break;
+ }
}
}
- if (paletteEmpty) {
- hb_log( "decvobsub: input color palette is empty; not demuxed properly?" );
+ if (!pv->palette_set) {
+ hb_log( "decvobsub: input color palette is empty!" );
}
return 0;
diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c
index 2ed6ef3e5..029207805 100644
--- a/libhb/deinterlace.c
+++ b/libhb/deinterlace.c
@@ -77,6 +77,7 @@ hb_filter_object_t hb_filter_deinterlace =
{
.id = HB_FILTER_DEINTERLACE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Deinterlace (ffmpeg or yadif/mcdeint)",
.settings = NULL,
.init = hb_deinterlace_init,
diff --git a/libhb/denoise.c b/libhb/denoise.c
index dfc58863d..48addf8e9 100644
--- a/libhb/denoise.c
+++ b/libhb/denoise.c
@@ -46,6 +46,7 @@ hb_filter_object_t hb_filter_denoise =
{
.id = HB_FILTER_DENOISE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Denoise (hqdn3d)",
.settings = NULL,
.init = hb_denoise_init,
diff --git a/libhb/detelecine.c b/libhb/detelecine.c
index 0437730f2..0ec02303a 100644
--- a/libhb/detelecine.c
+++ b/libhb/detelecine.c
@@ -98,6 +98,7 @@ hb_filter_object_t hb_filter_detelecine =
{
.id = HB_FILTER_DETELECINE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Detelecine (pullup)",
.settings = NULL,
.init = hb_detelecine_init,
diff --git a/libhb/dvd.c b/libhb/dvd.c
index 338dd12d1..f2e0ffeb3 100644
--- a/libhb/dvd.c
+++ b/libhb/dvd.c
@@ -496,12 +496,16 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur
subtitle->format = PICTURESUB;
subtitle->source = VOBSUB;
subtitle->config.dest = RENDERSUB; // By default render (burn-in) the VOBSUB.
+ subtitle->stream_type = 0xbd;
+ subtitle->substream_type = 0x20 + position;
+ subtitle->codec = WORK_DECVOBSUB;
subtitle->type = lang_extension;
memcpy( subtitle->palette,
vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->palette,
16 * sizeof( uint32_t ) );
+ subtitle->palette_set = 1;
switch( lang_extension )
{
diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c
index 52d062b06..8b356e188 100644
--- a/libhb/dvdnav.c
+++ b/libhb/dvdnav.c
@@ -646,12 +646,16 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura
subtitle->format = PICTURESUB;
subtitle->source = VOBSUB;
subtitle->config.dest = RENDERSUB; // By default render (burn-in) the VOBSUB.
+ subtitle->stream_type = 0xbd;
+ subtitle->substream_type = 0x20 + position;
+ subtitle->codec = WORK_DECVOBSUB;
subtitle->type = lang_extension;
memcpy( subtitle->palette,
ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->palette,
16 * sizeof( uint32_t ) );
+ subtitle->palette_set = 1;
switch( lang_extension )
{
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index 4a44d4343..089639d6d 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -164,7 +164,6 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
lavc_opts = hb_encopts_to_dict( job->advanced_opts, job->vcodec );
}
/* iterate through lavc_opts and have avutil parse the options for us */
- int ret;
AVDictionary * av_opts = NULL;
hb_dict_entry_t * entry = NULL;
while( ( entry = hb_dict_next( lavc_opts, entry ) ) )
diff --git a/libhb/hb.c b/libhb/hb.c
index 1dda37578..1b3b1c8b0 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -459,6 +459,7 @@ hb_handle_t * hb_init( int verbose, int update_check )
hb_register( &hb_decutf8sub );
hb_register( &hb_dectx3gsub );
hb_register( &hb_decssasub );
+ hb_register( &hb_decpgssub );
hb_register( &hb_encavcodec );
hb_register( &hb_encx264 );
hb_register( &hb_enctheora );
@@ -1244,6 +1245,7 @@ void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter, const char * se
else if( f->id == filter->id )
{
// Don't allow the same filter to be added twice
+ hb_filter_close( &filter );
return;
}
}
@@ -1569,7 +1571,7 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
{
subtitle = hb_list_item( title->list_subtitle, i );
if( strcmp( subtitle->iso639_2, audio_lang ) == 0 &&
- subtitle->source == VOBSUB )
+ hb_subtitle_can_force( subtitle->source ) )
{
/*
* Matched subtitle language with audio language, so
diff --git a/libhb/hb_dict.c b/libhb/hb_dict.c
index 31b5492ad..5912139d5 100644
--- a/libhb/hb_dict.c
+++ b/libhb/hb_dict.c
@@ -155,7 +155,8 @@ hb_dict_t * hb_encopts_to_dict( const char * encopts, int encoder )
hb_dict_t * dict = NULL;
if( encopts && *encopts )
{
- char *cur_opt, *opts_start, *name, *value;
+ char *cur_opt, *opts_start, *value;
+ const char *name;
dict = hb_dict_init( 10 );
if( !dict )
return NULL;
diff --git a/libhb/internal.h b/libhb/internal.h
index 0ae63924a..0d6ee2776 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -395,7 +395,8 @@ enum
WORK_ENC_CA_HAAC,
WORK_ENCAVCODEC_AUDIO,
WORK_MUX,
- WORK_READER
+ WORK_READER,
+ WORK_DECPGSSUB
};
extern hb_filter_object_t hb_filter_detelecine;
diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c
index 1bed15c49..1140bc5b0 100644
--- a/libhb/muxmkv.c
+++ b/libhb/muxmkv.c
@@ -322,9 +322,9 @@ static int MKVInit( hb_mux_object_t * m )
continue;
memset(track, 0, sizeof(mk_TrackConfig));
- switch (subtitle->format)
+ switch (subtitle->source)
{
- case PICTURESUB:
+ case VOBSUB:
track->codecID = MK_SUBTITLE_VOBSUB;
for (j = 0; j < 16; j++)
rgb[j] = hb_yuv2rgb(subtitle->palette[j]);
@@ -338,16 +338,20 @@ static int MKVInit( hb_mux_object_t * m )
track->codecPrivate = subidx;
track->codecPrivateSize = len + 1;
break;
- case TEXTSUB:
- if (subtitle->source == SSASUB)
- {
- track->codecID = MK_SUBTITLE_SSA;
- need_fonts = 1;
- track->codecPrivate = subtitle->extradata;
- track->codecPrivateSize = subtitle->extradata_size;
- }
- else
- track->codecID = MK_SUBTITLE_UTF8;
+ case PGSSUB:
+ track->codecID = "S_HDMV/PGS";
+ break;
+ case SSASUB:
+ track->codecID = MK_SUBTITLE_SSA;
+ need_fonts = 1;
+ track->codecPrivate = subtitle->extradata;
+ track->codecPrivateSize = subtitle->extradata_size;
+ break;
+ case CC608SUB:
+ case CC708SUB:
+ case UTF8SUB:
+ case TX3GSUB:
+ track->codecID = MK_SUBTITLE_UTF8;
break;
default:
continue;
diff --git a/libhb/ports.c b/libhb/ports.c
index bd3564be3..6ccbaede3 100644
--- a/libhb/ports.c
+++ b/libhb/ports.c
@@ -611,9 +611,7 @@ void hb_cond_wait( hb_cond_t * c, hb_lock_t * lock )
void hb_clock_gettime( struct timespec *tp )
{
struct timeval tv;
- time_t sec;
- sec = time( NULL );
gettimeofday( &tv, NULL );
tp->tv_sec = tv.tv_sec;
tp->tv_nsec = tv.tv_usec * 1000;
diff --git a/libhb/rendersub.c b/libhb/rendersub.c
index 8707bd3d2..40eaba5fe 100644
--- a/libhb/rendersub.c
+++ b/libhb/rendersub.c
@@ -38,6 +38,16 @@ static int ssa_work( hb_filter_object_t * filter,
static void ssa_close( hb_filter_object_t * filter );
+// PGS
+static int pgssub_init ( hb_filter_object_t * filter, hb_filter_init_t * init );
+
+static int pgssub_work ( hb_filter_object_t * filter,
+ hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out );
+
+static void pgssub_close( hb_filter_object_t * filter );
+
+
// Entry points
static int hb_rendersub_init( hb_filter_object_t * filter,
hb_filter_init_t * init );
@@ -52,6 +62,7 @@ hb_filter_object_t hb_filter_render_sub =
{
.id = HB_FILTER_RENDER_SUB,
.enforce_order = 1,
+ .init_index = 1,
.name = "Subtitle renderer",
.settings = NULL,
.init = hb_rendersub_init,
@@ -80,16 +91,15 @@ static void blend( hb_buffer_t *dst, hb_buffer_t *src, int left, int top )
}
ww = src->f.width;
- if( left + src->f.width > dst->f.width )
+ if( src->f.width - x0 > dst->f.width - left )
{
- ww = dst->f.width - ( left + src->f.width );
+ ww = dst->f.width - left + x0;
}
hh = src->f.height;
- if( top + src->f.height > dst->f.height )
+ if( src->f.height - y0 > dst->f.height - top )
{
- hh = dst->f.height - ( top + src->f.height );
+ hh = dst->f.height - top + y0;
}
-
// Blend luma
for( yy = y0; yy < hh; yy++ )
{
@@ -116,6 +126,7 @@ static void blend( hb_buffer_t *dst, hb_buffer_t *src, int left, int top )
hshift = 1;
if( dst->plane[1].width < dst->plane[0].width )
wshift = 1;
+
for( yy = y0 >> hshift; yy < hh >> hshift; yy++ )
{
u_in = src->plane[1].data + yy * src->plane[1].stride;
@@ -224,13 +235,14 @@ static void ApplyVOBSubs( hb_filter_private_t * pv, hb_buffer_t * buf )
int ii;
hb_buffer_t * sub;
- for( ii = 0; ii < hb_list_count( pv->sub_list ); ii++ )
+ for( ii = 0; ii < hb_list_count( pv->sub_list ); )
{
sub = hb_list_item( pv->sub_list, ii );
if( sub->s.stop <= buf->s.start )
{
// Subtitle stop is in the past, delete it
hb_list_rem( pv->sub_list, sub );
+ hb_buffer_close( &sub );
}
else if( sub->s.start <= buf->s.start )
{
@@ -241,6 +253,7 @@ static void ApplyVOBSubs( hb_filter_private_t * pv, hb_buffer_t * buf )
ApplySub( pv, buf, sub );
sub = sub->next;
}
+ ii++;
}
else
{
@@ -530,6 +543,116 @@ static int ssa_work( hb_filter_object_t * filter,
return HB_FILTER_OK;
}
+static void ApplyPGSSubs( hb_filter_private_t * pv, hb_buffer_t * buf )
+{
+ int index;
+ hb_buffer_t * old_sub;
+ hb_buffer_t * sub;
+
+ // Each PGS subtitle supersedes anything that preceded it.
+ // Find the active subtitle (if there is one), and delete
+ // everything before it.
+ for( index = hb_list_count( pv->sub_list ) - 1; index > 0; index-- )
+ {
+ sub = hb_list_item( pv->sub_list, index);
+ if ( sub->s.start <= buf->s.start )
+ {
+ while ( index > 0 )
+ {
+ old_sub = hb_list_item( pv->sub_list, index - 1);
+ hb_list_rem( pv->sub_list, old_sub );
+ hb_buffer_close( &old_sub );
+ index--;
+ }
+ }
+ }
+
+ // Some PGS subtitles have no content and only serve to clear
+ // the screen. If any of these are at the front of our list,
+ // we can now get rid of them.
+ while ( hb_list_count( pv->sub_list ) > 0 )
+ {
+ sub = hb_list_item( pv->sub_list, 0 );
+ if (sub->f.width != 0 && sub->f.height != 0)
+ break;
+
+ hb_list_rem( pv->sub_list, sub );
+ hb_buffer_close( &sub );
+ }
+
+ // Check to see if there's an active subtitle, and apply it.
+ if ( hb_list_count( pv->sub_list ) > 0)
+ {
+ sub = hb_list_item( pv->sub_list, 0 );
+ if ( sub->s.start <= buf->s.start )
+ {
+ while ( sub )
+ {
+ ApplySub( pv, buf, sub );
+ sub = sub->sub;
+ }
+ }
+ }
+}
+
+static int pgssub_init( hb_filter_object_t * filter,
+ hb_filter_init_t * init )
+{
+ hb_filter_private_t * pv = filter->private_data;
+
+ // PGS render filter has no settings
+ memcpy( pv->crop, init->crop, sizeof( int[4] ) );
+
+ pv->sub_list = hb_list_init();
+
+ return 0;
+}
+
+static void pgssub_close( hb_filter_object_t * filter )
+{
+ hb_filter_private_t * pv = filter->private_data;
+
+ if ( !pv )
+ {
+ return;
+ }
+
+ if ( pv->sub_list )
+ hb_list_empty( &pv->sub_list );
+
+ free( pv );
+ filter->private_data = NULL;
+}
+
+static int pgssub_work( hb_filter_object_t * filter,
+ hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out)
+{
+ hb_filter_private_t * pv = filter->private_data;
+ hb_buffer_t * in = *buf_in;
+ hb_buffer_t * sub;
+
+ if ( in->size <= 0 )
+ {
+ *buf_in = NULL;
+ *buf_out = in;
+ return HB_FILTER_DONE;
+ }
+
+ // Get any pending subtitles and add them to the active
+ // subtitle list
+ while ( ( sub = hb_fifo_get( filter->subtitle->fifo_out ) ) )
+ {
+ hb_list_add( pv->sub_list, sub );
+ }
+
+ ApplyPGSSubs( pv, in );
+ *buf_in = NULL;
+ *buf_out = in;
+
+ return HB_FILTER_OK;
+}
+
static int hb_rendersub_init( hb_filter_object_t * filter,
hb_filter_init_t * init )
{
@@ -568,6 +691,11 @@ static int hb_rendersub_init( hb_filter_object_t * filter,
return ssa_init( filter, init );
} break;
+ case PGSSUB:
+ {
+ return pgssub_init( filter, init );
+ } break;
+
default:
{
hb_log("rendersub: unsupported subtitle format %d", pv->type );
@@ -593,6 +721,11 @@ static int hb_rendersub_work( hb_filter_object_t * filter,
return ssa_work( filter, buf_in, buf_out );
} break;
+ case PGSSUB:
+ {
+ return pgssub_work( filter, buf_in, buf_out );
+ } break;
+
default:
{
hb_error("rendersub: unsupported subtitle format %d", pv->type );
@@ -616,6 +749,11 @@ static void hb_rendersub_close( hb_filter_object_t * filter )
ssa_close( filter );
} break;
+ case PGSSUB:
+ {
+ pgssub_close( filter );
+ } break;
+
default:
{
hb_error("rendersub: unsupported subtitle format %d", pv->type );
diff --git a/libhb/rotate.c b/libhb/rotate.c
index 5f9558764..a96e6927d 100644
--- a/libhb/rotate.c
+++ b/libhb/rotate.c
@@ -46,6 +46,7 @@ hb_filter_object_t hb_filter_rotate =
{
.id = HB_FILTER_ROTATE,
.enforce_order = 0,
+ .init_index = 2,
.name = "Rotate (rotate & flip image axes)",
.settings = NULL,
.init = hb_rotate_init,
diff --git a/libhb/scan.c b/libhb/scan.c
index 1ad8659b7..a3e6e1832 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -237,7 +237,7 @@ static void ScanFunc( void * _data )
for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
{
hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, j );
- if ( subtitle->source == VOBSUB )
+ if ( subtitle->source == VOBSUB || subtitle->source == PGSSUB )
{
subtitle->width = title->width;
subtitle->height = title->height;
diff --git a/libhb/stream.c b/libhb/stream.c
index 2c7c4f9a5..7961eebfb 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -30,9 +30,10 @@
* U - Unknown (to be determined by further processing)
* A - Audio
* V - Video
+ * S - Subtitle
* P - PCR
*/
-typedef enum { N, U, A, V, P } kind_t;
+typedef enum { N, U, A, V, P, S } kind_t;
typedef struct {
kind_t kind; /* not handled / unknown / audio / video */
int codec; /* HB worker object id of codec */
@@ -82,7 +83,7 @@ static const stream2codec_t st2codec[256] = {
st(0x8a, A, HB_ACODEC_DCA, 0, "DTS"),
- st(0x90, N, 0, 0, "PGS Subtitle"),
+ st(0x90, S, WORK_DECPGSSUB, 0, "PGS Subtitle"),
// 0x91 can be AC3 or BD Interactive Graphics Stream.
st(0x91, U, 0, 0, "AC3/IGS"),
st(0x92, N, 0, 0, "Subtitle"),
@@ -253,6 +254,7 @@ static int64_t pes_timestamp( const uint8_t *pes );
static int hb_ts_stream_init(hb_stream_t *stream);
static hb_buffer_t * hb_ts_stream_decode(hb_stream_t *stream);
static void hb_init_audio_list(hb_stream_t *stream, hb_title_t *title);
+static void hb_init_subtitle_list(hb_stream_t *stream, hb_title_t *title);
static int hb_ts_stream_find_pids(hb_stream_t *stream);
static void hb_ps_stream_init(hb_stream_t *stream);
@@ -947,6 +949,15 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title )
update_ts_streams( d, pid, stream_id_ext, stream_type, A, NULL );
}
+ hb_subtitle_t * subtitle;
+ for ( ii = 0; ( subtitle = hb_list_item( title->list_subtitle, ii ) ); ++ii )
+ {
+ pid = subtitle->id & 0xFFFF;
+ stream_type = subtitle->stream_type;
+
+ update_ts_streams( d, pid, 0, stream_type, S, NULL );
+ }
+
// When scanning, title->job == NULL. We don't need to wait for
// a PCR when scanning. In fact, it trips us up on the first
// preview of every title since we would have to read quite a
@@ -1035,6 +1046,7 @@ hb_title_t * hb_stream_title_scan(hb_stream_t *stream, hb_title_t * title)
// - For program streams read the first 4MB and take every unique
// audio stream we find.
hb_init_audio_list(stream, title);
+ hb_init_subtitle_list(stream, title);
// set the video id, codec & muxer
int idx = pes_index_of_video( stream );
@@ -2024,6 +2036,119 @@ static void set_audio_description(
// Sort specifies the index in the audio list where you would
// like sorted items to begin.
+static void pes_add_subtitle_to_title(
+ hb_stream_t *stream,
+ int idx,
+ hb_title_t *title,
+ int sort)
+{
+ hb_pes_stream_t *pes = &stream->pes.list[idx];
+
+ // Sort by id when adding to the list
+ // This assures that they are always displayed in the same order
+ int id = get_id( pes );
+ int i;
+ hb_subtitle_t *tmp = NULL;
+
+ int count = hb_list_count( title->list_subtitle );
+
+ // Don't add the same audio twice. Search for audio.
+ for ( i = 0; i < count; i++ )
+ {
+ tmp = hb_list_item( title->list_subtitle, i );
+ if ( id == tmp->id )
+ return;
+ }
+
+ hb_subtitle_t *subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
+ iso639_lang_t * lang;
+
+ subtitle->track = idx;
+ subtitle->id = id;
+ lang = lang_for_code( pes->lang_code );
+ 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);
+
+ switch ( pes->codec )
+ {
+ case WORK_DECPGSSUB:
+ subtitle->source = PGSSUB;
+ subtitle->format = PICTURESUB;
+ subtitle->config.dest = RENDERSUB;
+ break;
+ case WORK_DECVOBSUB:
+ subtitle->source = VOBSUB;
+ subtitle->format = PICTURESUB;
+ subtitle->config.dest = RENDERSUB;
+ break;
+ default:
+ // Unrecognized, don't add to list
+ hb_log("unregonized subtitle!");
+ free( subtitle );
+ return;
+ }
+ subtitle->reg_desc = stream->reg_desc;
+ subtitle->stream_type = pes->stream_type;
+ subtitle->substream_type = pes->stream_id_ext;
+ subtitle->codec = pes->codec;
+
+ // Create a default palette since vob files do not include the
+ // vobsub palette.
+ if ( subtitle->source == VOBSUB )
+ {
+ subtitle->palette[0] = 0x108080;
+ subtitle->palette[1] = 0x108080;
+ subtitle->palette[2] = 0x108080;
+ subtitle->palette[3] = 0xbff000;
+
+ subtitle->palette[4] = 0xbff000;
+ subtitle->palette[5] = 0x108080;
+ subtitle->palette[6] = 0x108080;
+ subtitle->palette[7] = 0x108080;
+
+ subtitle->palette[8] = 0xbff000;
+ subtitle->palette[9] = 0x108080;
+ subtitle->palette[10] = 0x108080;
+ subtitle->palette[11] = 0x108080;
+
+ subtitle->palette[12] = 0x108080;
+ subtitle->palette[13] = 0xbff000;
+ subtitle->palette[14] = 0x108080;
+ subtitle->palette[15] = 0x108080;
+ }
+
+ hb_log("stream id 0x%x (type 0x%x substream 0x%x) subtitle 0x%x",
+ pes->stream_id, pes->stream_type, pes->stream_id_ext, subtitle->id);
+
+ // Search for the sort position
+ if ( sort >= 0 )
+ {
+ sort = sort < count ? sort : count;
+ for ( i = sort; i < count; i++ )
+ {
+ tmp = hb_list_item( title->list_subtitle, i );
+ int sid = tmp->id & 0xffff;
+ int ssid = tmp->id >> 16;
+ if ( pes->stream_id < sid )
+ break;
+ else if ( pes->stream_id <= sid &&
+ pes->stream_id_ext <= ssid )
+ {
+ break;
+ }
+ }
+ hb_list_insert( title->list_subtitle, i, subtitle );
+ }
+ else
+ {
+ hb_list_add( title->list_subtitle, subtitle );
+ }
+}
+
+// Sort specifies the index in the audio list where you would
+// like sorted items to begin.
static void pes_add_audio_to_title(
hb_stream_t *stream,
int idx,
@@ -2090,6 +2215,42 @@ static void pes_add_audio_to_title(
}
}
+static void hb_init_subtitle_list(hb_stream_t *stream, hb_title_t *title)
+{
+ int ii;
+ int map_idx;
+ int largest = -1;
+
+ // First add all that were found in a map.
+ for ( map_idx = 0; 1; map_idx++ )
+ {
+ for ( ii = 0; ii < stream->pes.count; ii++ )
+ {
+ if ( stream->pes.list[ii].stream_kind == S )
+ {
+ if ( stream->pes.list[ii].map_idx == map_idx )
+ {
+ pes_add_subtitle_to_title( stream, ii, title, -1 );
+ }
+ if ( stream->pes.list[ii].map_idx > largest )
+ largest = stream->pes.list[ii].map_idx;
+ }
+ }
+ if ( map_idx > largest )
+ break;
+ }
+
+ int count = hb_list_count( title->list_audio );
+ // Now add the reset. Sort them by stream id.
+ for ( ii = 0; ii < stream->pes.count; ii++ )
+ {
+ if ( stream->pes.list[ii].stream_kind == S )
+ {
+ pes_add_subtitle_to_title( stream, ii, title, count );
+ }
+ }
+}
+
static void hb_init_audio_list(hb_stream_t *stream, hb_title_t *title)
{
int ii;
@@ -2206,6 +2367,19 @@ static int hb_ts_stream_init(hb_stream_t *stream)
stream->ts.list[i].is_pcr ? " (PCR)" : "");
}
}
+ hb_log(" Subtitle PIDS : ");
+ for (i = 0; i < stream->ts.count; i++)
+ {
+ if ( ts_stream_kind( stream, i ) == S )
+ {
+ hb_log( " 0x%x type %s (0x%x)%s",
+ stream->ts.list[i].pid,
+ stream_type_name2(stream,
+ &stream->pes.list[stream->ts.list[i].pes_list]),
+ ts_stream_type( stream, i ),
+ stream->ts.list[i].is_pcr ? " (PCR)" : "");
+ }
+ }
hb_log(" Other PIDS : ");
for (i = 0; i < stream->ts.count; i++)
{
@@ -2281,6 +2455,19 @@ static void hb_ps_stream_init(hb_stream_t *stream)
stream->pes.list[i].stream_type );
}
}
+ hb_log(" Subtitle Streams : ");
+ for (i = 0; i < stream->pes.count; i++)
+ {
+ if ( stream->pes.list[i].stream_kind == S )
+ {
+ hb_log( " 0x%x-0x%x type %s (0x%x)",
+ stream->pes.list[i].stream_id,
+ stream->pes.list[i].stream_id_ext,
+ stream_type_name2(stream,
+ &stream->pes.list[i]),
+ stream->pes.list[i].stream_type );
+ }
+ }
hb_log(" Other Streams : ");
for (i = 0; i < stream->pes.count; i++)
{
@@ -3728,10 +3915,10 @@ static void hb_ps_stream_find_streams(hb_stream_t *stream)
// Check dvd substream id
if ( ssid >= 0x20 && ssid <= 0x37 )
{
- // Skip dvd subtitles
int idx = update_ps_streams( stream, pes_info.stream_id,
pes_info.bd_substream_id, 0, -1 );
- stream->pes.list[idx].stream_kind = N;
+ stream->pes.list[idx].stream_kind = S;
+ stream->pes.list[idx].codec = WORK_DECVOBSUB;
strncpy(stream->pes.list[idx].codec_name,
"DVD Subtitle", 80);
continue;
@@ -4122,6 +4309,7 @@ static void hb_ts_resolve_pid_types(hb_stream_t *stream)
// stype == 0 indicates a type not in st2codec table
if ( stype != 0 &&
( ts_stream_kind( stream, ii ) == A ||
+ ts_stream_kind( stream, ii ) == S ||
ts_stream_kind( stream, ii ) == V ) )
{
// Assuming there are no substreams.
@@ -4203,6 +4391,7 @@ static void hb_ps_resolve_stream_types(hb_stream_t *stream)
// stype == 0 indicates a type not in st2codec table
if ( stype != 0 &&
( stream->pes.list[ii].stream_kind == A ||
+ stream->pes.list[ii].stream_kind == S ||
stream->pes.list[ii].stream_kind == V ) )
{
stream->pes.list[ii].codec = st2codec[stype].codec;
@@ -5049,6 +5238,7 @@ static int ffmpeg_parse_vobsub_extradata_mkv( AVCodecContext *codec, hb_subtitle
int i;
for (i=0; i<16; i++)
subtitle->palette[i] = hb_rgb2yuv(rgb[i]);
+ subtitle->palette_set = 1;
return 0;
}
else
@@ -5072,6 +5262,7 @@ static int ffmpeg_parse_vobsub_extradata_mp4( AVCodecContext *codec, hb_subtitle
codec->extradata[j+1] << 16 | // Y
codec->extradata[j+2] << 8 | // Cb
codec->extradata[j+3] << 0; // Cr
+ subtitle->palette_set = 1;
}
if (codec->width <= 0 || codec->height <= 0)
{
@@ -5113,6 +5304,7 @@ static void add_ffmpeg_subtitle( hb_title_t *title, hb_stream_t *stream, int id
subtitle->format = PICTURESUB;
subtitle->source = VOBSUB;
subtitle->config.dest = RENDERSUB; // By default render (burn-in) the VOBSUB.
+ subtitle->codec = WORK_DECVOBSUB;
if ( ffmpeg_parse_vobsub_extradata( codec, subtitle ) )
hb_log( "add_ffmpeg_subtitle: malformed extradata for VOB subtitle track; "
"subtitle colors likely to be wrong" );
@@ -5121,16 +5313,25 @@ static void add_ffmpeg_subtitle( hb_title_t *title, hb_stream_t *stream, int id
subtitle->format = TEXTSUB;
subtitle->source = UTF8SUB;
subtitle->config.dest = PASSTHRUSUB;
+ subtitle->codec = WORK_DECUTF8SUB;
break;
case CODEC_ID_MOV_TEXT: // TX3G
subtitle->format = TEXTSUB;
subtitle->source = TX3GSUB;
subtitle->config.dest = PASSTHRUSUB;
+ subtitle->codec = WORK_DECTX3GSUB;
break;
case CODEC_ID_SSA:
subtitle->format = TEXTSUB;
subtitle->source = SSASUB;
subtitle->config.dest = PASSTHRUSUB;
+ subtitle->codec = WORK_DECSSASUB;
+ break;
+ case CODEC_ID_HDMV_PGS_SUBTITLE:
+ subtitle->format = PICTURESUB;
+ subtitle->source = PGSSUB;
+ subtitle->config.dest = RENDERSUB;
+ subtitle->codec = WORK_DECPGSSUB;
break;
default:
hb_log( "add_ffmpeg_subtitle: unknown subtitle stream type: 0x%x", (int) codec->codec_id );
diff --git a/libhb/sync.c b/libhb/sync.c
index c9a4eebe6..c76cc45d2 100644
--- a/libhb/sync.c
+++ b/libhb/sync.c
@@ -69,10 +69,6 @@ typedef struct
uint64_t st_counts[4];
uint64_t st_dates[4];
uint64_t st_first;
-
- /* Subtitles */
- hb_buffer_t * sub_list; /* list of subtitles to be passed thru or rendered */
- hb_buffer_t * sub_tail; /* list of subtitles to be passed thru or rendered */
} hb_sync_video_t;
struct hb_work_private_s
diff --git a/libhb/vfr.c b/libhb/vfr.c
index 9c3e2e2a8..7c70c21d4 100644
--- a/libhb/vfr.c
+++ b/libhb/vfr.c
@@ -46,6 +46,7 @@ hb_filter_object_t hb_filter_vfr =
{
.id = HB_FILTER_VFR,
.enforce_order = 1,
+ .init_index = 0,
.name = "Framerate Shaper",
.settings = NULL,
.init = hb_vfr_init,
diff --git a/libhb/work.c b/libhb/work.c
index f9d7bf656..eab4db821 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -390,17 +390,20 @@ void hb_display_job_info( hb_job_t * job )
{
/* For SRT, print offset and charset too */
hb_log( " * subtitle track %i, %s (id 0x%x) %s [%s] -> %s%s, offset: %"PRId64", charset: %s",
- subtitle->track, subtitle->lang, subtitle->id, "Text", "SRT", "Pass-Through",
+ subtitle->out_track, subtitle->lang, subtitle->id,
+ "Text", "SRT", "Pass-Through",
subtitle->config.default_track ? ", Default" : "",
subtitle->config.offset, subtitle->config.src_codeset );
}
else
{
- hb_log( " * subtitle track %i, %s (id 0x%x) %s [%s] -> %s%s%s", subtitle->track, subtitle->lang, subtitle->id,
+ hb_log( " * subtitle track %i, %s (id 0x%x) %s [%s] -> %s%s%s",
+ subtitle->out_track, subtitle->lang, subtitle->id,
subtitle->format == PICTURESUB ? "Picture" : "Text",
hb_subsource_name( subtitle->source ),
job->indepth_scan ? "Foreign Audio Search" :
- subtitle->config.dest == RENDERSUB ? "Render/Burn in" : "Pass-Through",
+ subtitle->config.dest == RENDERSUB ?
+ "Render/Burn in" : "Pass-Through",
subtitle->config.force ? ", Forced Only" : "",
subtitle->config.default_track ? ", Default" : "" );
}
@@ -489,6 +492,46 @@ void correct_framerate( hb_job_t * job )
interjob->vrate_base = job->vrate_base;
}
+void hb_filter_init_next( hb_list_t * list, int *score, int *ret_pos )
+{
+ int count = hb_list_count( list );
+ int pos = *ret_pos + 1;
+ int ii = 0;
+ if ( pos == 0 )
+ {
+ hb_filter_object_t * filter = hb_list_item( list, pos );
+ if ( filter->init_index == *score )
+ {
+ *ret_pos = pos;
+ return;
+ }
+ pos++;
+ }
+ while (1)
+ {
+ if ( pos == count )
+ {
+ pos = 0;
+ (*score)++;
+ }
+ hb_filter_object_t * filter = hb_list_item( list, pos );
+ if ( filter->init_index == *score )
+ {
+ *ret_pos = pos;
+ return;
+ }
+ pos++;
+ ii++;
+ if (ii > count)
+ {
+ // This is an error that should never happen
+ hb_error("internal error during filter initialization");
+ *ret_pos = -1;
+ return;
+ }
+ }
+}
+
/**
* Job initialization rountine.
* Initializes fifos.
@@ -529,11 +572,139 @@ static void do_job( hb_job_t * job )
hb_log( "starting job" );
+ /*
+ * Look for the scanned subtitle in the existing subtitle list
+ * select_subtitle implies that we did a scan.
+ */
+ if ( !job->indepth_scan && interjob->select_subtitle &&
+ ( job->pass == 0 || job->pass == 2 ) )
+ {
+ /*
+ * Disable forced subtitles if we didn't find any in the scan
+ * so that we display normal subtitles instead.
+ */
+ if( interjob->select_subtitle->config.force &&
+ interjob->select_subtitle->forced_hits == 0 )
+ {
+ interjob->select_subtitle->config.force = 0;
+ }
+ for( i=0; i < hb_list_count(title->list_subtitle); i++ )
+ {
+ subtitle = hb_list_item( title->list_subtitle, i );
+
+ if( subtitle )
+ {
+ /*
+ * Remove the scanned subtitle from the subtitle list if
+ * it would result in an identical duplicate subtitle track
+ * or an emty track (forced and no forced hits).
+ */
+ if( ( interjob->select_subtitle->id == subtitle->id ) &&
+ ( ( interjob->select_subtitle->forced_hits == 0 &&
+ subtitle->config.force ) ||
+ ( subtitle->config.force == interjob->select_subtitle->config.force ) ) )
+ {
+ *subtitle = *(interjob->select_subtitle);
+ free( interjob->select_subtitle );
+ interjob->select_subtitle = NULL;
+ break;
+ }
+ }
+ }
+
+ if( interjob->select_subtitle )
+ {
+ /*
+ * Its not in the existing list
+ *
+ * Must be second pass of a two pass with subtitle scan enabled, so
+ * add the subtitle that we found on the first pass for use in this
+ * pass.
+ */
+ hb_list_add( title->list_subtitle, interjob->select_subtitle );
+ interjob->select_subtitle = NULL;
+ }
+ }
+
+ if ( !job->indepth_scan )
+ {
+ // Sanitize subtitles
+ uint8_t one_burned = 0;
+ for( i=0; i < hb_list_count(title->list_subtitle); )
+ {
+ subtitle = hb_list_item( title->list_subtitle, i );
+
+ if ( subtitle->config.dest == RENDERSUB )
+ {
+ if ( one_burned )
+ {
+ if ( !hb_subtitle_can_pass(subtitle->source, job->mux) )
+ {
+ hb_log( "More than one subtitle burn-in requested, dropping track %d.", i );
+ hb_list_rem( title->list_subtitle, subtitle );
+ free( subtitle );
+ continue;
+ }
+ else
+ {
+ hb_log( "More than one subtitle burn-in requested. Changing track %d to soft subtitle.", i );
+ subtitle->config.dest = PASSTHRUSUB;
+ }
+ }
+ else if ( !hb_subtitle_can_burn(subtitle->source) )
+ {
+ hb_log( "Subtitle burn-in requested and input track can not be rendered. Changing track %d to soft subtitle.", i );
+ subtitle->config.dest = PASSTHRUSUB;
+ }
+ else
+ {
+ one_burned = 1;
+ }
+ }
+
+ if ( subtitle->config.dest == PASSTHRUSUB &&
+ !hb_subtitle_can_pass(subtitle->source, job->mux) )
+ {
+ if ( !one_burned )
+ {
+ hb_log( "Subtitle pass-thru requested and input track is not compatible with container. Changing track %d to burned-in subtitle.", i );
+ subtitle->config.dest = RENDERSUB;
+ subtitle->config.default_track = 0;
+ one_burned = 1;
+ }
+ else
+ {
+ hb_log( "Subtitle pass-thru requested and input track is not compatible with container. One track already burned, dropping track %d.", i );
+ hb_list_rem( title->list_subtitle, subtitle );
+ free( subtitle );
+ continue;
+ }
+ }
+ /* Adjust output track number, in case we removed one.
+ * Output tracks sadly still need to be in sequential order.
+ * Note: out.track starts at 1, i starts at 0 */
+ subtitle->out_track = ++i;
+ }
+ if ( one_burned )
+ {
+ hb_filter_object_t * filter;
+
+ // Add subtitle rendering filter
+ // Note that if the filter is already in the filter chain, this
+ // has no effect. Note also that this means the front-end is
+ // not required to add the subtitle rendering filter since
+ // we will always try to do it here.
+ filter = hb_filter_init(HB_FILTER_RENDER_SUB);
+ hb_add_filter( job, filter, NULL );
+ }
+ }
+
// Filters have an effect on settings.
// So initialize the filters and update the job.
if( job->list_filter && hb_list_count( job->list_filter ) )
{
hb_filter_init_t init;
+ int pos = -1, score = 0;
init.job = job;
init.pix_fmt = PIX_FMT_YUV420P;
@@ -547,7 +718,19 @@ static void do_job( hb_job_t * job )
init.cfr = 0;
for( i = 0; i < hb_list_count( job->list_filter ); i++ )
{
- hb_filter_object_t * filter = hb_list_item( job->list_filter, i );
+ // Some filters need to be initialized in a different order
+ // than they are executed in the pipeline. e.g. rendersub
+ // needs to be initialized after cropscale so that it knows
+ // the crop settings, but it needs to be executed before
+ // cropscale. so hb_filter_init_next() finds returns the
+ // position of filters in initialization order.
+ hb_filter_init_next( job->list_filter, &score, &pos );
+ if( pos == -1)
+ {
+ // This is an error that should never happen!
+ break;
+ }
+ hb_filter_object_t * filter = hb_list_item( job->list_filter, pos );
if( filter->init( filter, &init ) )
{
hb_log( "Failure to initialise filter '%s', disabling",
@@ -847,60 +1030,6 @@ static void do_job( hb_job_t * job )
w->fifo_in = job->fifo_mpeg2;
w->fifo_out = job->fifo_raw;
- /*
- * Look for the scanned subtitle in the existing subtitle list
- * select_subtitle implies that we did a scan.
- */
- if ( !job->indepth_scan && interjob->select_subtitle &&
- ( job->pass == 0 || job->pass == 2 ) )
- {
- /*
- * Disable forced subtitles if we didn't find any in the scan
- * so that we display normal subtitles instead.
- */
- if( interjob->select_subtitle->config.force &&
- interjob->select_subtitle->forced_hits == 0 )
- {
- interjob->select_subtitle->config.force = 0;
- }
- for( i=0; i < hb_list_count(title->list_subtitle); i++ )
- {
- subtitle = hb_list_item( title->list_subtitle, i );
-
- if( subtitle )
- {
- /*
- * Remove the scanned subtitle from the subtitle list if
- * it would result in an identical duplicate subtitle track
- * or an emty track (forced and no forced hits).
- */
- if( ( interjob->select_subtitle->id == subtitle->id ) &&
- ( ( interjob->select_subtitle->forced_hits == 0 &&
- subtitle->config.force ) ||
- ( subtitle->config.force == interjob->select_subtitle->config.force ) ) )
- {
- *subtitle = *(interjob->select_subtitle);
- free( interjob->select_subtitle );
- interjob->select_subtitle = NULL;
- break;
- }
- }
- }
-
- if( interjob->select_subtitle )
- {
- /*
- * Its not in the existing list
- *
- * Must be second pass of a two pass with subtitle scan enabled, so
- * add the subtitle that we found on the first pass for use in this
- * pass.
- */
- hb_list_add( title->list_subtitle, interjob->select_subtitle );
- interjob->select_subtitle = NULL;
- }
- }
-
for( i=0; i < hb_list_count(title->list_subtitle); i++ )
{
subtitle = hb_list_item( title->list_subtitle, i );
@@ -920,60 +1049,17 @@ static void do_job( hb_job_t * job )
subtitle->fifo_sync = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
subtitle->fifo_out = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
- if( (!job->indepth_scan || job->select_subtitle_config.force) &&
- subtitle->source == VOBSUB ) {
- /*
- * Don't add threads for subtitles when we are scanning, unless
- * looking for forced subtitles.
- */
- 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 );
- }
-
- if( !job->indepth_scan && subtitle->source == CC608SUB )
- {
- w = hb_get_work( WORK_DECCC608 );
- w->fifo_in = subtitle->fifo_in;
- w->fifo_out = subtitle->fifo_raw;
- hb_list_add( job->list_work, w );
- }
-
- if( !job->indepth_scan && subtitle->source == SRTSUB )
- {
- w = hb_get_work( WORK_DECSRTSUB );
- w->fifo_in = subtitle->fifo_in;
- w->fifo_out = subtitle->fifo_raw;
- w->subtitle = subtitle;
- hb_list_add( job->list_work, w );
- }
-
- if( !job->indepth_scan && subtitle->source == UTF8SUB )
- {
- w = hb_get_work( WORK_DECUTF8SUB );
- w->fifo_in = subtitle->fifo_in;
- w->fifo_out = subtitle->fifo_raw;
- hb_list_add( job->list_work, w );
- }
-
- if( !job->indepth_scan && subtitle->source == TX3GSUB )
+ if( job->indepth_scan &&
+ !( job->select_subtitle_config.force &&
+ hb_subtitle_can_force( subtitle->source ) ) )
{
- w = hb_get_work( WORK_DECTX3GSUB );
- w->fifo_in = subtitle->fifo_in;
- w->fifo_out = subtitle->fifo_raw;
- hb_list_add( job->list_work, w );
- }
-
- if( !job->indepth_scan && subtitle->source == SSASUB )
- {
- w = hb_get_work( WORK_DECSSASUB );
- w->fifo_in = subtitle->fifo_in;
- w->fifo_out = subtitle->fifo_raw;
- w->subtitle = subtitle;
- hb_list_add( job->list_work, w );
+ continue;
}
+ w = hb_get_work( subtitle->codec );
+ w->fifo_in = subtitle->fifo_in;
+ w->fifo_out = subtitle->fifo_raw;
+ w->subtitle = subtitle;
+ hb_list_add( job->list_work, w );
}
}
diff --git a/macosx/Controller.m b/macosx/Controller.m
index 53a64b9d6..88a146ae0 100644
--- a/macosx/Controller.m
+++ b/macosx/Controller.m
@@ -3185,28 +3185,6 @@ bool one_burned = FALSE;
}
else
{
-
- /* for the actual source tracks, we must subtract the non source entries so
- * that the menu index matches the source subtitle_list index for convenience */
- if (i == 0)
- {
- /* for the first track, the source tracks start at menu index 2 ( None is 0,
- * Foreign Language Search is 1) so subtract 2 */
- subtitle = subtitle - 2;
- }
- else
- {
- /* for all other tracks, the source tracks start at menu index 1 (None is 0)
- * so subtract 1. */
-
- subtitle = subtitle - 1;
- }
-
- /* We are setting a source subtitle so access the source subtitle info */
- hb_subtitle_t * subt;
-
- subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
-
/* if we are getting the subtitles from an external srt file */
if ([[tempObject objectForKey:@"subtitleSourceTrackType"] isEqualToString:@"SRT"])
{
@@ -3225,35 +3203,48 @@ bool one_burned = FALSE;
sub_config.default_track = def;
hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]);
+ continue;
}
- if (subt != NULL)
+ /* for the actual source tracks, we must subtract the non source entries so
+ * that the menu index matches the source subtitle_list index for convenience */
+ if( i == 0 )
+ {
+ /* for the first track, the source tracks start at menu index 2 ( None is 0,
+ * Foreign Language Search is 1) so subtract 2 */
+ subtitle = subtitle - 2;
+ }
+ else
+ {
+ /* for all other tracks, the source tracks start at menu index 1 (None is 0)
+ * so subtract 1. */
+ subtitle = subtitle - 1;
+ }
+
+ /* We are setting a source subtitle so access the source subtitle info */
+ hb_subtitle_t * subt = (hb_subtitle_t *) hb_list_item( title->list_subtitle, subtitle );
+
+ if( subt != NULL )
{
hb_subtitle_config_t sub_config = subt->config;
- if ( !burned && subt->format == PICTURESUB )
+ if( !burned && hb_subtitle_can_pass( subt->source, job->mux ) )
{
sub_config.dest = PASSTHRUSUB;
}
- else if ( burned && subt->format == PICTURESUB )
+ else if( hb_subtitle_can_burn( subt->source ) )
{
// Only allow one subtitle to be burned into the video
- if (one_burned)
+ if( one_burned )
continue;
one_burned = TRUE;
- }
-
- /* Besides VOBSUBS we can also burn in SSA text subs */
- if (subt->source == SSASUB && burned)
- {
sub_config.dest = RENDERSUB;
}
sub_config.force = force;
sub_config.default_track = def;
hb_subtitle_add( job, &sub_config, subtitle );
- }
-
+ }
}
}
i++;
@@ -3724,28 +3715,6 @@ bool one_burned = FALSE;
}
else
{
-
- /* for the actual source tracks, we must subtract the non source entries so
- * that the menu index matches the source subtitle_list index for convenience */
- if (i == 0)
- {
- /* for the first track, the source tracks start at menu index 2 ( None is 0,
- * Foreign Language Search is 1) so subtract 2 */
- subtitle = subtitle - 2;
- }
- else
- {
- /* for all other tracks, the source tracks start at menu index 1 (None is 0)
- * so subtract 1. */
-
- subtitle = subtitle - 1;
- }
-
- /* We are setting a source subtitle so access the source subtitle info */
- hb_subtitle_t * subt;
-
- subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
-
/* if we are getting the subtitles from an external srt file */
if ([[tempObject objectForKey:@"subtitleSourceTrackType"] isEqualToString:@"SRT"])
{
@@ -3764,36 +3733,48 @@ bool one_burned = FALSE;
sub_config.default_track = def;
hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]);
+ continue;
+ }
+
+ /* for the actual source tracks, we must subtract the non source entries so
+ * that the menu index matches the source subtitle_list index for convenience */
+ if( i == 0 )
+ {
+ /* for the first track, the source tracks start at menu index 2 ( None is 0,
+ * Foreign Language Search is 1) so subtract 2 */
+ subtitle = subtitle - 2;
+ }
+ else
+ {
+ /* for all other tracks, the source tracks start at menu index 1 (None is 0)
+ * so subtract 1. */
+ subtitle = subtitle - 1;
}
+ /* We are setting a source subtitle so access the source subtitle info */
+ hb_subtitle_t * subt = (hb_subtitle_t *) hb_list_item( title->list_subtitle, subtitle );
- if (subt != NULL)
+ if( subt != NULL )
{
hb_subtitle_config_t sub_config = subt->config;
- if ( !burned && subt->format == PICTURESUB )
+ if( !burned && hb_subtitle_can_pass( subt->source, job->mux ) )
{
sub_config.dest = PASSTHRUSUB;
}
- else if ( burned )
+ else if( hb_subtitle_can_burn( subt->source ) )
{
// Only allow one subtitle to be burned into the video
- if (one_burned)
+ if( one_burned )
continue;
one_burned = TRUE;
- }
-
- /* Besides VOBSUBS we can also burn in SSA text subs */
- if (subt->source == SSASUB && burned)
- {
sub_config.dest = RENDERSUB;
}
-
+
sub_config.force = force;
sub_config.default_track = def;
hb_subtitle_add( job, &sub_config, subtitle );
- }
-
+ }
}
}
i++;
diff --git a/macosx/HBSubtitles.m b/macosx/HBSubtitles.m
index 1d0c45ae6..f84749303 100644
--- a/macosx/HBSubtitles.m
+++ b/macosx/HBSubtitles.m
@@ -3,18 +3,10 @@
This file is part of the HandBrake source code.
Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
-//
#import "HBSubtitles.h"
#include "hb.h"
-
-
-
-
-
-
-
@implementation HBSubtitles
- (id)init
{
@@ -285,8 +277,8 @@
subtitle = (hb_subtitle_t *) hb_list_item( fTitle->list_subtitle, i );
sub_config = subtitle->config;
- int canBeBurnedIn = subtitle->source == VOBSUB || subtitle->source == SSASUB;
- int supportsForcedFlags = subtitle->source == VOBSUB;
+ int canBeBurnedIn = hb_subtitle_can_burn( subtitle->source );
+ int supportsForcedFlags = hb_subtitle_can_force( subtitle->source );
/* create a dictionary of source subtitle information to store in our array */
NSMutableDictionary *newSubtitleSourceTrack = [[NSMutableDictionary alloc] init];
@@ -294,7 +286,7 @@
[newSubtitleSourceTrack setObject:[NSNumber numberWithInt:i] forKey:@"sourceTrackNum"];
/* Human-readable representation of subtitle->source */
NSString *subSourceName = [NSString stringWithUTF8String:hb_subsource_name( subtitle->source )];
- NSString *bitmapOrText = subtitle->source == PICTURESUB ? @"Bitmap" : @"Text";
+ NSString *bitmapOrText = subtitle->format == PICTURESUB ? @"Bitmap" : @"Text";
/* Subtitle Source track name */
NSString *popupName = [NSString stringWithFormat:@"%d - %@ - (%@) (%@)",i,[NSString stringWithUTF8String:subtitle->lang],bitmapOrText,subSourceName];
[newSubtitleSourceTrack setObject:popupName forKey:@"sourceTrackName"];
@@ -769,7 +761,9 @@
*/
if (container == HB_MUX_MP4 && [anObject intValue] != 0)
{
- if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] isEqualToString:[NSString stringWithUTF8String:hb_subsource_name( VOBSUB )]])
+ NSString *subtitleSourceTrackType = [[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"];
+ if ([subtitleSourceTrackType isEqualToString:[NSString stringWithUTF8String:hb_subsource_name( VOBSUB )]] ||
+ [subtitleSourceTrackType isEqualToString:[NSString stringWithUTF8String:hb_subsource_name( PGSSUB )]])
{
/* lets see if there are currently any burned in subs specified */
NSEnumerator *enumerator = [subtitleArray objectEnumerator];
@@ -783,7 +777,7 @@
}
}
/* if we have no current vobsub set to burn it in ... burn it in by default */
- if(!subtrackBurnedInFound)
+ if (!subtrackBurnedInFound)
{
[[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:1] forKey:@"subtitleTrackBurned"];
/* Burned In and Default are mutually exclusive */
diff --git a/test/test.c b/test/test.c
index 504a3507d..758dd0fa2 100644
--- a/test/test.c
+++ b/test/test.c
@@ -2229,11 +2229,10 @@ static int HandleEvents( hb_handle_t * h )
force = test_sub_list(subforce, i+1);
- int supports_burn =
- ( subtitle->source == VOBSUB ) ||
- ( subtitle->source == SSASUB );
+ int supports_burn = hb_subtitle_can_burn( subtitle->source );
- if ( burn && supports_burn )
+ if ( ( burn && supports_burn ) ||
+ !hb_subtitle_can_pass( subtitle->source, mux ) )
{
// Only allow one subtitle to be burned into video
if ( sub_burned )