From 4d9d707e3246292263a4a2f43da1824d679230b7 Mon Sep 17 00:00:00 2001 From: Vivia Nikolaidou Date: Thu, 10 May 2012 23:08:21 +0300 Subject: [PATCH] discoverer: Wait until an update/filler newsegment event or buffer for subtitle streams This makes sure that we wait until we received all tags for the subtitle streams and have all information that is collected by the discoverer. Fixes bug #673504. --- gst-libs/gst/pbutils/gstdiscoverer.c | 110 +++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/pbutils/gstdiscoverer.c b/gst-libs/gst/pbutils/gstdiscoverer.c index 9d9cee28b0..96c52ea19a 100644 --- a/gst-libs/gst/pbutils/gstdiscoverer.c +++ b/gst-libs/gst/pbutils/gstdiscoverer.c @@ -71,6 +71,12 @@ typedef struct GstTagList *tags; } PrivateStream; +typedef struct +{ + GstPad *pad; + gulong id; +} PadWithId; + struct _GstDiscovererPrivate { gboolean async; @@ -89,6 +95,9 @@ struct _GstDiscovererPrivate /* TRUE if discoverer has been started */ gboolean running; + /* TRUE if ASYNC_DONE has been received (need to check for subtitle tags) */ + gboolean async_done; + /* current items */ GstDiscovererInfo *current_info; GError *current_error; @@ -97,6 +106,9 @@ struct _GstDiscovererPrivate /* List of private streams */ GList *streams; + /* List of these sinks and their handler IDs (to remove the probe) */ + GList *pending_subtitle_pads; + /* Global elements */ GstBin *pipeline; GstElement *uridecodebin; @@ -262,9 +274,12 @@ gst_discoverer_init (GstDiscoverer * dc) dc->priv->timeout = DEFAULT_PROP_TIMEOUT; dc->priv->async = FALSE; + dc->priv->async_done = FALSE; dc->priv->lock = g_mutex_new (); + dc->priv->pending_subtitle_pads = NULL; + GST_LOG ("Creating pipeline"); dc->priv->pipeline = (GstBin *) gst_pipeline_new ("Discoverer"); GST_LOG_OBJECT (dc, "Creating uridecodebin"); @@ -461,6 +476,57 @@ is_subtitle_caps (const GstCaps * caps) return ret; } +static void +free_pad_id (PadWithId * d) +{ + + gst_pad_remove_data_probe (d->pad, d->id); + gst_object_unref (d->pad); + g_slice_free (PadWithId, d); + +} + +static void +got_subtitle_data (GstPad * pad, GstMiniObject * obj, GstDiscoverer * dc) +{ + + GList *item = NULL; + gboolean update; + gboolean is_event; + + is_event = GST_IS_EVENT (obj); + + if (!(GST_IS_BUFFER (obj) || (is_event + && GST_EVENT_TYPE ((GstEvent *) obj) == GST_EVENT_NEWSEGMENT))) + return; + + if (is_event) { + gst_event_parse_new_segment ((GstEvent *) obj, &update, NULL, NULL, NULL, + NULL, NULL); + if (!update) + return; + } + + DISCO_LOCK (dc); + for (item = dc->priv->pending_subtitle_pads; item; item = item->next) { + PadWithId *pad_id = (PadWithId *) item->data; + if (pad_id->pad == pad) { + dc->priv->pending_subtitle_pads = + g_list_remove_link (dc->priv->pending_subtitle_pads, item); + free_pad_id (pad_id); + break; + } + } + + if (dc->priv->pending_subtitle_pads == NULL) { + GstMessage *msg = gst_message_new_application (NULL, + gst_structure_empty_new ("DiscovererDone")); + gst_element_post_message ((GstElement *) dc->priv->pipeline, msg); + } + DISCO_UNLOCK (dc); + +} + static void uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstDiscoverer * dc) @@ -486,10 +552,23 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad, caps = gst_pad_query_caps (pad, NULL); + sinkpad = gst_element_get_static_pad (ps->queue, "sink"); + if (sinkpad == NULL) + goto error; + if (is_subtitle_caps (caps)) { /* Subtitle streams are sparse and may not provide any information - don't * wait for data to preroll */ + PadWithId *pad_id; + pad_id = g_slice_new0 (PadWithId); + pad_id->pad = GST_PAD_CAST (gst_object_ref (sinkpad)); + pad_id->id = + gst_pad_add_data_probe (sinkpad, (GCallback) got_subtitle_data, dc); g_object_set (ps->sink, "async", FALSE, NULL); + DISCO_LOCK (dc); + dc->priv->pending_subtitle_pads = + g_list_prepend (dc->priv->pending_subtitle_pads, pad_id); + DISCO_UNLOCK (dc); } gst_caps_unref (caps); @@ -504,9 +583,6 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad, if (!gst_element_sync_state_with_parent (ps->queue)) goto error; - sinkpad = gst_element_get_static_pad (ps->queue, "sink"); - if (sinkpad == NULL) - goto error; if (gst_pad_link_full (pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK) goto error; @@ -1175,10 +1251,30 @@ handle_message (GstDiscoverer * dc, GstMessage * msg) done = TRUE; break; + case GST_MESSAGE_APPLICATION:{ + const gchar *name; + gboolean async_done; + name = gst_structure_get_name (gst_message_get_structure (msg)); + /* Maybe ASYNC_DONE is received & we're just waiting for subtitle tags */ + DISCO_LOCK (dc); + async_done = dc->priv->async_done; + DISCO_UNLOCK (dc); + if (g_str_equal (name, "DiscovererDone") && async_done) + return TRUE; + break; + } + case GST_MESSAGE_ASYNC_DONE: if (GST_MESSAGE_SRC (msg) == (GstObject *) dc->priv->pipeline) { GST_DEBUG ("Finished changing state asynchronously"); - done = TRUE; + DISCO_LOCK (dc); + if (dc->priv->pending_subtitle_pads == NULL) { + done = TRUE; + } else { + /* Remember that ASYNC_DONE has been received, wait for subtitles */ + dc->priv->async_done = TRUE; + } + DISCO_UNLOCK (dc); } break; @@ -1233,7 +1329,6 @@ handle_message (GstDiscoverer * dc, GstMessage * msg) return done; } - static void handle_current_sync (GstDiscoverer * dc) { @@ -1320,6 +1415,11 @@ discoverer_cleanup (GstDiscoverer * dc) dc->priv->current_info = NULL; + g_list_foreach (dc->priv->pending_subtitle_pads, (GFunc) free_pad_id, NULL); + g_list_free (dc->priv->pending_subtitle_pads); + dc->priv->pending_subtitle_pads = NULL; + dc->priv->async_done = FALSE; + /* Try popping the next uri */ if (dc->priv->async) { if (dc->priv->pending_uris != NULL) {