sig_id =
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (element), "signal_id"));
- GST_LOG ("removing preroll signal %s", GST_ELEMENT_NAME (element));
- g_signal_handler_disconnect (G_OBJECT (element), sig_id);
+ if (sig_id) {
+ GST_LOG ("removing preroll signal %s", GST_ELEMENT_NAME (element));
+ g_signal_handler_disconnect (G_OBJECT (element), sig_id);
+ }
}
}
{
GST_DEBUG ("queue %s overrun", GST_ELEMENT_NAME (element));
- group_commit (play_base_bin, FALSE, FALSE);
+ group_commit (play_base_bin, FALSE,
+ GST_OBJECT_PARENT (GST_OBJECT_CAST (element)) ==
+ GST_OBJECT (play_base_bin->subtitle));
g_signal_handlers_disconnect_by_func (element,
G_CALLBACK (queue_overrun), play_base_bin);
+ /* We have disconnected this signal, remove the signal_id from the object
+ data */
+ g_object_set_data (G_OBJECT (element), "signal_id", NULL);
}
/* Used for time-based buffering. */
return NULL;
subparse = gst_element_factory_make ("decodebin", "subtitle-decoder");
- subbin = gst_bin_new ("subbin");
+ subbin = gst_bin_new ("subtitle-bin");
gst_bin_add_many (GST_BIN (subbin), source, subparse, NULL);
gst_element_link (source, subparse);
/* do subs */
if (subbin) {
-#if 0
- gint sig4, sig5, sig6;
GstElement *db;
play_base_bin->subtitle = subbin;
db = gst_bin_get_by_name (GST_BIN (subbin), "subtitle-decoder");
- /* don't add yet, because we will preroll, and subs shouldn't
- * preroll (we shouldn't preroll more than once source). */
- gst_element_set_state (subbin, GST_STATE_PAUSED);
-
/* do type detection, without adding (so no preroll) */
- g_signal_connect (G_OBJECT (db),
- "new-decoded-pad", G_CALLBACK (new_decoded_pad), play_base_bin);
+ g_signal_connect (G_OBJECT (db), "new-decoded-pad",
+ G_CALLBACK (new_decoded_pad), play_base_bin);
g_signal_connect (G_OBJECT (db), "no-more-pads",
G_CALLBACK (no_more_pads), play_base_bin);
+ g_signal_connect (G_OBJECT (db), "unknown-type",
+ G_CALLBACK (unknown_type), play_base_bin);
if (!play_base_bin->is_stream) {
- sig4 = g_signal_connect (G_OBJECT (db),
- "unknown-type", G_CALLBACK (unknown_type), play_base_bin);
- sig5 = g_signal_connect (G_OBJECT (subbin), "error",
- G_CALLBACK (thread_error), error);
-
/* either when the queues are filled or when the decoder element
* has no more dynamic streams, the cond is unlocked. We can remove
* the signal handlers then
*/
- g_mutex_lock (play_base_bin->group_lock);
- if (gst_element_set_state (subbin, GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_SUCCESS) {
- GST_DEBUG ("waiting for first group...");
- sig6 = g_signal_connect (G_OBJECT (subbin),
- "state-changed", G_CALLBACK (state_change), play_base_bin);
- g_cond_wait (play_base_bin->group_cond, play_base_bin->group_lock);
- GST_DEBUG ("group done !");
- } else {
- GST_DEBUG ("state change failed, subtitle cannot be loaded");
- sig6 = 0;
- }
- g_mutex_unlock (play_base_bin->group_lock);
-
- if (sig6 != 0)
- g_signal_handler_disconnect (G_OBJECT (subbin), sig6);
-
- g_signal_handler_disconnect (G_OBJECT (subbin), sig5);
- g_signal_handler_disconnect (G_OBJECT (db), sig4);
gst_element_set_state (subbin, GST_STATE_PAUSED);
+ GROUP_LOCK (play_base_bin);
+ GST_DEBUG ("waiting for first group...");
+ GROUP_WAIT (play_base_bin);
+ GST_DEBUG ("group done !");
+ GROUP_UNLOCK (play_base_bin);
+
if (!play_base_bin->building_group ||
play_base_bin->building_group->type[GST_STREAM_TYPE_TEXT - 1].npads ==
0) {
- if (*error) {
- g_error_free (*error);
- *error = NULL;
- }
GST_DEBUG ("No subtitle found - ignoring");
- gst_object_unref (play_base_bin->subtitle);
+ gst_element_set_state (subbin, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (play_base_bin->subtitle));
play_base_bin->subtitle = NULL;
} else {
GST_DEBUG ("Subtitle set-up successful");
}
}
-#endif
}
/* now see if the source element emits raw audio/video all by itself,
g_signal_connect (G_OBJECT (play_base_bin->decoder),
"unknown-type", G_CALLBACK (unknown_type), play_base_bin);
+ if (play_base_bin->subtitle) {
+ gst_bin_add (GST_BIN (play_base_bin), play_base_bin->subtitle);
+ }
+
play_base_bin->need_rebuild = FALSE;
return TRUE;
GST_LOG ("Muting group type: %d", type);
g_object_set (sel, "active-pad", "", NULL);
} else {
- GST_LOG ("Unuting group type: %d", type);
+ GST_LOG ("Unmuting group type: %d", type);
}
mute_group_type (group, type, !have_active);
}
gst_object_unref (play_bin->pending_visualisation);
play_bin->pending_visualisation = NULL;
}
+ if (play_bin->textoverlay_element != NULL) {
+ gst_object_unref (play_bin->textoverlay_element);
+ play_bin->textoverlay_element = NULL;
+ }
g_free (play_bin->font_desc);
play_bin->font_desc = NULL;
GstElement *element, *csp, *overlay, *vbin;
GstPad *pad;
+ /* Create our bin */
+ element = gst_bin_new ("textbin");
+
+ /* Text overlay */
overlay = gst_element_factory_make ("textoverlay", "overlay");
+
+ /* Create the video rendering bin */
+ vbin = gen_video_element (play_bin);
+
+ /* If no overlay return the video bin */
+ if (!overlay) {
+ GST_WARNING ("No overlay (pango) element, subtitles disabled");
+ return vbin;
+ }
+
+ /* Set some parameters */
g_object_set (G_OBJECT (overlay),
"halign", "center", "valign", "bottom", NULL);
- play_bin->textoverlay_element = overlay;
if (play_bin->font_desc) {
g_object_set (G_OBJECT (play_bin->textoverlay_element),
"font-desc", play_bin->font_desc, NULL);
}
- vbin = gen_video_element (play_bin);
- if (!overlay) {
- g_warning ("No overlay (pango) element, subtitles disabled");
- return vbin;
- }
+
+ /* Take a ref */
+ play_bin->textoverlay_element = GST_ELEMENT (gst_object_ref (overlay));
+
csp = gst_element_factory_make ("ffmpegcolorspace", "subtitlecsp");
- element = gst_bin_new ("textbin");
- gst_element_link_many (csp, overlay, vbin, NULL);
+
+ /* Add our elements */
gst_bin_add_many (GST_BIN (element), csp, overlay, vbin, NULL);
+ /* Link */
+ gst_element_link_pads (csp, "src", overlay, "video_sink");
+ gst_element_link_pads (overlay, "src", vbin, "sink");
+
+ /* Add ghost pads on the subtitle bin */
pad = gst_element_get_pad (overlay, "text_sink");
-#define gst_element_add_ghost_pad(element, pad, name) \
- gst_element_add_pad (element, gst_ghost_pad_new (name, pad))
- gst_element_add_ghost_pad (element, pad, "text_sink");
+ gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad));
gst_object_unref (pad);
pad = gst_element_get_pad (csp, "sink");
- gst_element_add_ghost_pad (element, pad, "sink");
+ gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
gst_object_unref (pad);
+ /* Set state to READY */
+ gst_element_set_state (element, GST_STATE_READY);
+
return element;
}
gst_element_link_pads (volume, "src", sink, "sink");
pad = gst_element_get_pad (conv, "sink");
- gst_element_add_ghost_pad (element, pad, "sink");
+ gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
gst_object_unref (pad);
gst_element_set_state (element, GST_STATE_READY);
gst_object_unref (pad);
pad = gst_element_get_pad (tee, "sink");
- gst_element_add_ghost_pad (element, pad, "sink");
+ gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
gst_object_unref (pad);
return element;
play_bin->frame = NULL;
}
- play_bin->textoverlay_element = NULL;
+ if (play_bin->textoverlay_element) {
+ gst_object_unref (play_bin->textoverlay_element);
+ play_bin->textoverlay_element = NULL;
+ }
}
/* loop over the streams and set up the pipeline to play this
* one can switch the streams.
*/
static gboolean
-add_sink (GstPlayBin * play_bin, GstElement * sink, GstPad * srcpad)
+add_sink (GstPlayBin * play_bin, GstElement * sink, GstPad * srcpad,
+ GstPad * subtitle_pad)
{
GstPad *sinkpad;
GstPadLinkReturn linkres;
if (GST_PAD_LINK_FAILED (linkres))
goto link_failed;
+ if (GST_IS_PAD (subtitle_pad)) {
+ sinkpad = gst_element_get_pad (sink, "text_sink");
+ linkres = gst_pad_link (subtitle_pad, sinkpad);
+ gst_object_unref (sinkpad);
+ }
+
+ /* try to link the subtitle pad of the sink to the stream */
+ if (GST_PAD_LINK_FAILED (linkres)) {
+ goto subtitle_failed;
+ }
+
/* we got the sink succesfully linked, now keep the sink
- * in out internal list */
+ * in our internal list */
play_bin->sinks = g_list_prepend (play_bin->sinks, sink);
return TRUE;
gst_bin_remove (GST_BIN (play_bin), sink);
return FALSE;
}
+subtitle_failed:
+ {
+ gchar *capsstr;
+ GstCaps *caps;
+
+ /* could not link this stream */
+ caps = gst_pad_get_caps (subtitle_pad);
+ capsstr = gst_caps_to_string (caps);
+ GST_DEBUG_OBJECT (play_bin,
+ "subtitle link failed when adding sink, caps %s, reason %d", capsstr,
+ linkres);
+ g_free (capsstr);
+ g_free (caps);
+
+ return TRUE;
+ }
}
static gboolean
GList *streaminfo = NULL, *s;
gboolean need_vis = FALSE;
gboolean need_text = FALSE;
- GstPad *textsrcpad = NULL, *textsinkpad = NULL, *pad;
+ GstPad *textsrcpad = NULL, *pad = NULL;
GstElement *sink;
gboolean res = TRUE;
return FALSE;
pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_AUDIO - 1].preroll,
"src");
- res = add_sink (play_bin, sink, pad);
+ res = add_sink (play_bin, sink, pad, NULL);
gst_object_unref (pad);
}
/* link video */
if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0) {
if (need_text) {
- sink = gen_text_element (play_bin);
+ GstObject *parent = NULL, *grandparent = NULL;
+ GstPad *ghost = NULL;
- textsinkpad = gst_element_get_pad (sink, "text_sink");
+ sink = gen_text_element (play_bin);
textsrcpad =
gst_element_get_pad (group->type[GST_STREAM_TYPE_TEXT - 1].preroll,
"src");
- gst_pad_link (textsrcpad, textsinkpad);
- gst_object_unref (textsinkpad);
- gst_object_unref (textsrcpad);
+ /* This pad is from subtitle-bin, we need to create a ghost pad to have
+ common grandparents */
+ parent = gst_object_get_parent (GST_OBJECT (textsrcpad));
+ if (!parent) {
+ GST_WARNING_OBJECT (textsrcpad, "subtitle pad has no parent !");
+ gst_object_unref (textsrcpad);
+ textsrcpad = NULL;
+ goto beach;
+ }
+
+ grandparent = gst_object_get_parent (parent);
+ if (!grandparent) {
+ GST_WARNING_OBJECT (textsrcpad, "subtitle pad has no grandparent !");
+ gst_object_unref (parent);
+ gst_object_unref (textsrcpad);
+ textsrcpad = NULL;
+ goto beach;
+ }
+
+ ghost = gst_ghost_pad_new ("text_src", textsrcpad);
+ if (!GST_IS_PAD (ghost)) {
+ GST_WARNING_OBJECT (textsrcpad, "failed creating ghost pad for "
+ "subtitle-bin");
+ gst_object_unref (parent);
+ gst_object_unref (grandparent);
+ gst_object_unref (textsrcpad);
+ textsrcpad = NULL;
+ goto beach;
+ }
+
+ if (gst_element_add_pad (GST_ELEMENT (grandparent), ghost)) {
+ gst_object_unref (textsrcpad);
+ textsrcpad = ghost;
+ } else {
+ GST_WARNING_OBJECT (ghost, "failed adding ghost pad on subtitle-bin");
+ gst_object_unref (ghost);
+ gst_object_unref (textsrcpad);
+ textsrcpad = NULL;
+ }
+
+ gst_object_unref (parent);
+ gst_object_unref (grandparent);
} else {
sink = gen_video_element (play_bin);
}
+ beach:
if (!sink)
return FALSE;
pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_VIDEO - 1].preroll,
"src");
- res = add_sink (play_bin, sink, pad);
+ res = add_sink (play_bin, sink, pad, textsrcpad);
gst_object_unref (pad);
}