X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst-libs%2Fgst%2Fpbutils%2Fgstdiscoverer.c;h=756b16417ebf4b0ca6fc56fa3a96b48502d52743;hb=e44dd9db8f767f6dd2b157b285774d5938c3fc75;hp=6a1dbc822878e1ea50fcac3e09ddff2ac601dbb3;hpb=7012e88090e69339c60a4eb9449f7a7e39ca6aa3;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst-libs/gst/pbutils/gstdiscoverer.c b/gst-libs/gst/pbutils/gstdiscoverer.c index 6a1dbc8..756b164 100644 --- a/gst-libs/gst/pbutils/gstdiscoverer.c +++ b/gst-libs/gst/pbutils/gstdiscoverer.c @@ -50,6 +50,8 @@ #include "pbutils-marshal.h" #include "pbutils-private.h" +#include "gst/glib-compat-private.h" + GST_DEBUG_CATEGORY_STATIC (discoverer_debug); #define GST_CAT_DEFAULT discoverer_debug @@ -233,7 +235,8 @@ gst_discoverer_class_init (GstDiscovererClass * klass) g_signal_new ("discovered", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDiscovererClass, discovered), NULL, NULL, pbutils_marshal_VOID__POINTER_BOXED, - G_TYPE_NONE, 2, GST_TYPE_DISCOVERER_INFO, GST_TYPE_G_ERROR); + G_TYPE_NONE, 2, GST_TYPE_DISCOVERER_INFO, + G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE); } static void @@ -410,10 +413,11 @@ gst_discoverer_set_timeout (GstDiscoverer * dc, GstClockTime timeout) DISCO_UNLOCK (dc); } -static GstProbeReturn -_event_probe (GstPad * pad, GstProbeType type, GstEvent * event, - PrivateStream * ps) +static GstPadProbeReturn +_event_probe (GstPad * pad, GstPadProbeInfo * info, PrivateStream * ps) { + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) { GstTagList *tl = NULL, *tmp; @@ -436,22 +440,25 @@ _event_probe (GstPad * pad, GstProbeType type, GstEvent * event, DISCO_UNLOCK (ps->dc); } - return GST_PROBE_OK; + return GST_PAD_PROBE_OK; } +static GstStaticCaps subtitle_caps = GST_STATIC_CAPS ("text/plain; " + "text/x-pango-markup; subpicture/x-pgs; subpicture/x-dvb; " + "application/x-subtitle-unknown; application/x-ssa; application/x-ass; " + "subtitle/x-kate; application/x-kate; video/x-dvd-subpicture"); + static gboolean is_subtitle_caps (const GstCaps * caps) { - static GstCaps *subs_caps = NULL; + GstCaps *subs_caps; + gboolean ret; - if (!subs_caps) { - subs_caps = gst_caps_from_string ("text/plain; text/x-pango-markup; " - "subpicture/x-pgs; subpicture/x-dvb; application/x-subtitle-unknown; " - "application/x-ssa; application/x-ass; subtitle/x-kate; " - "application/x-kate; video/x-dvd-subpicture; "); - } + subs_caps = gst_static_caps_get (&subtitle_caps); + ret = gst_caps_can_intersect (caps, subs_caps); + gst_caps_unref (subs_caps); - return gst_caps_can_intersect (caps, subs_caps); + return ret; } static void @@ -477,7 +484,7 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad, g_object_set (ps->sink, "silent", TRUE, NULL); g_object_set (ps->queue, "max-size-buffers", 1, "silent", TRUE, NULL); - caps = gst_pad_get_caps (pad, NULL); + caps = gst_pad_query_caps (pad, NULL); if (is_subtitle_caps (caps)) { /* Subtitle streams are sparse and may not provide any information - don't @@ -506,7 +513,7 @@ uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad, gst_object_unref (sinkpad); /* Add an event probe */ - gst_pad_add_probe (pad, GST_PROBE_TYPE_EVENT, + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) _event_probe, ps, NULL); DISCO_LOCK (dc); @@ -584,7 +591,7 @@ collect_stream_information (GstDiscoverer * dc, PrivateStream * ps, guint idx) gchar *stname; stname = g_strdup_printf ("stream-%02d", idx); - st = gst_structure_empty_new (stname); + st = gst_structure_new_empty (stname); g_free (stname); /* Get caps */ @@ -592,7 +599,7 @@ collect_stream_information (GstDiscoverer * dc, PrivateStream * ps, guint idx) if (!caps) { GST_WARNING ("Couldn't get negotiated caps from %s:%s", GST_DEBUG_PAD_NAME (ps->pad)); - caps = gst_pad_get_caps (ps->pad, NULL); + caps = gst_pad_query_caps (ps->pad, NULL); } if (caps) { GST_DEBUG ("Got caps %" GST_PTR_FORMAT, caps); @@ -601,11 +608,28 @@ collect_stream_information (GstDiscoverer * dc, PrivateStream * ps, guint idx) gst_caps_unref (caps); } if (ps->tags) - gst_structure_id_set (st, _TAGS_QUARK, GST_TYPE_STRUCTURE, ps->tags, NULL); + gst_structure_id_set (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, ps->tags, NULL); return st; } +/* takes ownership of new_tags, may replace *taglist with a new one */ +static void +gst_discoverer_merge_and_replace_tags (GstTagList ** taglist, + GstTagList * new_tags) +{ + if (new_tags == NULL) + return; + + if (*taglist == NULL) { + *taglist = new_tags; + return; + } + + gst_tag_list_insert (*taglist, new_tags, GST_TAG_MERGE_REPLACE); + gst_tag_list_free (new_tags); +} + /* Parses a set of caps and tags in st and populates a GstDiscovererStreamInfo * structure (parent, if !NULL, otherwise it allocates one) */ @@ -614,7 +638,8 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, GstDiscovererStreamInfo * parent) { GstCaps *caps; - GstStructure *caps_st, *tags_st; + GstStructure *caps_st; + GstTagList *tags_st; const gchar *name; int tmp; guint utmp; @@ -622,7 +647,7 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, if (!st || !gst_structure_id_has_field (st, _CAPS_QUARK)) { GST_WARNING ("Couldn't find caps !"); if (parent) - return parent; + return gst_discoverer_stream_info_ref (parent); else return (GstDiscovererStreamInfo *) g_object_new (GST_TYPE_DISCOVERER_STREAM_INFO, NULL); @@ -636,11 +661,11 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, GstDiscovererAudioInfo *info; if (parent) - info = (GstDiscovererAudioInfo *) parent; + info = (GstDiscovererAudioInfo *) gst_discoverer_stream_info_ref (parent); else { info = (GstDiscovererAudioInfo *) g_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO, NULL); - info->parent.caps = caps; + info->parent.caps = gst_caps_ref (caps); } if (gst_structure_get_int (caps_st, "rate", &tmp)) @@ -653,20 +678,16 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, info->depth = (guint) tmp; if (gst_structure_id_has_field (st, _TAGS_QUARK)) { - gst_structure_id_get (st, _TAGS_QUARK, - GST_TYPE_STRUCTURE, &tags_st, NULL); - if (gst_structure_get_uint (tags_st, GST_TAG_BITRATE, &utmp) || - gst_structure_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp)) + gst_structure_id_get (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, &tags_st, NULL); + if (gst_tag_list_get_uint (tags_st, GST_TAG_BITRATE, &utmp) || + gst_tag_list_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp)) info->bitrate = utmp; - if (gst_structure_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp)) + if (gst_tag_list_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp)) info->max_bitrate = utmp; /* FIXME: Is it worth it to remove the tags we've parsed? */ - info->parent.tags = gst_tag_list_merge (info->parent.tags, - (GstTagList *) tags_st, GST_TAG_MERGE_REPLACE); - - gst_structure_free (tags_st); + gst_discoverer_merge_and_replace_tags (&info->parent.tags, tags_st); } if (!info->language && ((GstDiscovererStreamInfo *) info)->tags) { @@ -677,6 +698,7 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, } } + gst_caps_unref (caps); return (GstDiscovererStreamInfo *) info; } else if (g_str_has_prefix (name, "video/") || @@ -685,14 +707,18 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, GstVideoInfo vinfo; if (parent) - info = (GstDiscovererVideoInfo *) parent; + info = (GstDiscovererVideoInfo *) gst_discoverer_stream_info_ref (parent); else { info = (GstDiscovererVideoInfo *) g_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO, NULL); - info->parent.caps = caps; + info->parent.caps = gst_caps_ref (caps); } - if (gst_video_info_from_caps (&vinfo, caps)) { + /* FIXME : gst_video_info_from_caps only works with raw caps, + * wouldn't we want to get all the info below for non-raw caps ? + */ + if (g_str_has_prefix (name, "video/x-raw") && + gst_video_info_from_caps (&vinfo, caps)) { info->width = (guint) vinfo.width; info->height = (guint) vinfo.height; @@ -708,49 +734,45 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, } if (gst_structure_id_has_field (st, _TAGS_QUARK)) { - gst_structure_id_get (st, _TAGS_QUARK, - GST_TYPE_STRUCTURE, &tags_st, NULL); - if (gst_structure_get_uint (tags_st, GST_TAG_BITRATE, &utmp) || - gst_structure_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp)) + gst_structure_id_get (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, &tags_st, NULL); + if (gst_tag_list_get_uint (tags_st, GST_TAG_BITRATE, &utmp) || + gst_tag_list_get_uint (tags_st, GST_TAG_NOMINAL_BITRATE, &utmp)) info->bitrate = utmp; - if (gst_structure_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp)) + if (gst_tag_list_get_uint (tags_st, GST_TAG_MAXIMUM_BITRATE, &utmp)) info->max_bitrate = utmp; /* FIXME: Is it worth it to remove the tags we've parsed? */ - info->parent.tags = gst_tag_list_merge (info->parent.tags, - (GstTagList *) tags_st, GST_TAG_MERGE_REPLACE); - gst_structure_free (tags_st); + gst_discoverer_merge_and_replace_tags (&info->parent.tags, + (GstTagList *) tags_st); } + gst_caps_unref (caps); return (GstDiscovererStreamInfo *) info; } else if (is_subtitle_caps (caps)) { GstDiscovererSubtitleInfo *info; if (parent) - info = (GstDiscovererSubtitleInfo *) parent; + info = + (GstDiscovererSubtitleInfo *) gst_discoverer_stream_info_ref (parent); else { info = (GstDiscovererSubtitleInfo *) g_object_new (GST_TYPE_DISCOVERER_SUBTITLE_INFO, NULL); - info->parent.caps = caps; + info->parent.caps = gst_caps_ref (caps); } if (gst_structure_id_has_field (st, _TAGS_QUARK)) { const gchar *language; - gst_structure_id_get (st, _TAGS_QUARK, - GST_TYPE_STRUCTURE, &tags_st, NULL); + gst_structure_id_get (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, &tags_st, NULL); language = gst_structure_get_string (caps_st, GST_TAG_LANGUAGE_CODE); if (language) info->language = g_strdup (language); /* FIXME: Is it worth it to remove the tags we've parsed? */ - info->parent.tags = gst_tag_list_merge (info->parent.tags, - (GstTagList *) tags_st, GST_TAG_MERGE_REPLACE); - gst_structure_free (tags_st); - + gst_discoverer_merge_and_replace_tags (&info->parent.tags, tags_st); } if (!info->language && ((GstDiscovererStreamInfo *) info)->tags) { @@ -761,6 +783,7 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, } } + gst_caps_unref (caps); return (GstDiscovererStreamInfo *) info; } else { @@ -768,20 +791,19 @@ collect_information (GstDiscoverer * dc, const GstStructure * st, GstDiscovererStreamInfo *info; if (parent) - info = parent; + info = gst_discoverer_stream_info_ref (parent); else { info = (GstDiscovererStreamInfo *) g_object_new (GST_TYPE_DISCOVERER_STREAM_INFO, NULL); - info->caps = caps; + info->caps = gst_caps_ref (caps); } if (gst_structure_id_get (st, _TAGS_QUARK, - GST_TYPE_STRUCTURE, &tags_st, NULL)) { - info->tags = gst_tag_list_merge (info->tags, (GstTagList *) tags_st, - GST_TAG_MERGE_REPLACE); - gst_structure_free (tags_st); + GST_TYPE_TAG_LIST, &tags_st, NULL)) { + gst_discoverer_merge_and_replace_tags (&info->tags, tags_st); } + gst_caps_unref (caps); return info; } @@ -805,8 +827,10 @@ find_stream_for_node (GstDiscoverer * dc, const GstStructure * topology) gst_structure_id_get (topology, _TOPOLOGY_PAD_QUARK, GST_TYPE_PAD, &pad, NULL); - if (!dc->priv->streams) + if (!dc->priv->streams) { + gst_object_unref (pad); return NULL; + } for (i = 0, tmp = dc->priv->streams; tmp; tmp = tmp->next, i++) { ps = (PrivateStream *) tmp->data; @@ -827,9 +851,9 @@ find_stream_for_node (GstDiscoverer * dc, const GstStructure * topology) } static gboolean -child_is_raw_stream (GstCaps * parent, GstCaps * child) +child_is_raw_stream (const GstCaps * parent, const GstCaps * child) { - GstStructure *st1, *st2; + const GstStructure *st1, *st2; const gchar *name1, *name2; st1 = gst_caps_get_structure (parent, 0); @@ -898,30 +922,29 @@ parse_stream_topology (GstDiscoverer * dc, const GstStructure * topology, /* We sometimes get an extra sub-stream from the parser. If this is * the case, we just replace the parent caps with this stream's caps * since they might contain more information */ - gst_caps_unref (parent->caps); - parent->caps = caps; + gst_caps_replace (&parent->caps, caps); parse_stream_topology (dc, st, parent); add_to_list = FALSE; - } else if (child_is_raw_stream (parent->caps, caps)) { /* This is the "raw" stream corresponding to the parent. This * contains more information than the parent, tags etc. */ parse_stream_topology (dc, st, parent); add_to_list = FALSE; - gst_caps_unref (caps); - } else { GstDiscovererStreamInfo *next = parse_stream_topology (dc, st, NULL); res->next = next; next->previous = res; } + gst_caps_unref (caps); } } if (add_to_list) { dc->priv->current_info->stream_list = g_list_append (dc->priv->current_info->stream_list, res); + } else { + gst_discoverer_stream_info_unref (res); } } else if (GST_VALUE_HOLDS_LIST (nval)) { @@ -945,7 +968,7 @@ parse_stream_topology (GstDiscoverer * dc, const GstStructure * topology, GstTagList *tmp; gst_structure_id_get (topology, _TAGS_QUARK, - GST_TYPE_STRUCTURE, &tags, NULL); + GST_TYPE_TAG_LIST, &tags, NULL); GST_DEBUG ("Merge tags %" GST_PTR_FORMAT, tags); @@ -1001,6 +1024,31 @@ discoverer_collect (GstDiscoverer * dc) if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur)) { GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur)); dc->priv->current_info->duration = (guint64) dur; + } else { + GstStateChangeReturn sret; + + /* Some parsers may not even return a rough estimate right away, e.g. + * because they've only processed a single frame so far, so if we + * didn't get a duration the first time, spin a bit and try again. + * Ugly, but still better than making parsers or other elements return + * completely bogus values. We need some API extensions to solve this + * better. */ + GST_INFO ("No duration yet, try a bit harder.."); + sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + if (sret != GST_STATE_CHANGE_FAILURE) { + int i; + + for (i = 0; i < 2; ++i) { + g_usleep (G_USEC_PER_SEC / 20); + if (gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur) + && dur > 0) { + GST_DEBUG ("Got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (dur)); + dc->priv->current_info->duration = (guint64) dur; + break; + } + } + gst_element_set_state (pipeline, GST_STATE_PAUSED); + } } if (dc->priv->seeking_query) { @@ -1039,8 +1087,8 @@ discoverer_collect (GstDiscoverer * dc) gst_caps_get_structure (dc->priv->current_info->stream_info->caps, 0); if (g_str_has_prefix (gst_structure_get_name (st), "image/")) - ((GstDiscovererVideoInfo *) dc->priv->current_info->stream_info)-> - is_image = TRUE; + ((GstDiscovererVideoInfo *) dc->priv->current_info-> + stream_info)->is_image = TRUE; } } @@ -1140,8 +1188,12 @@ handle_message (GstDiscoverer * dc, GstMessage * msg) GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg), "Setting result to MISSING_PLUGINS"); dc->priv->current_info->result = GST_DISCOVERER_MISSING_PLUGINS; + if (dc->priv->current_info->misc) + gst_structure_free (dc->priv->current_info->misc); dc->priv->current_info->misc = gst_structure_copy (structure); } else if (sttype == _STREAM_TOPOLOGY_QUARK) { + if (dc->priv->current_topology) + gst_structure_free (dc->priv->current_topology); dc->priv->current_topology = gst_structure_copy (structure); } } @@ -1192,7 +1244,6 @@ handle_current_sync (GstDiscoverer * dc) done = handle_message (dc, msg); gst_message_unref (msg); } - } while (!done && (g_timer_elapsed (timer, NULL) < deadline)); /* return result */ @@ -1464,7 +1515,7 @@ gst_discoverer_stop (GstDiscoverer * discoverer) * A copy of @uri will be made internally, so the caller can safely g_free() * afterwards. * - * Returns: %TRUE if the @uri was succesfully appended to the list of pending + * Returns: %TRUE if the @uri was successfully appended to the list of pending * uris, else %FALSE * * Since: 0.10.31