static gboolean gst_csp_structure_is_alpha (GstStructure * s) { GQuark name; name = gst_structure_get_name_id (s); if (name == _QRAWRGB) { return gst_structure_id_has_field (s, _QALPHAMASK); } else if (name == _QRAWYUV) { guint32 fourcc; if (!gst_structure_get_fourcc (s, "format", &fourcc)) return FALSE; return (fourcc == GST_MAKE_FOURCC ('A', 'Y', 'U', 'V')); } return FALSE; }
static GstStructure * find_stream_for_node (GstDiscoverer * dc, const GstStructure * topology) { GstPad *pad; GstPad *target_pad = NULL; GstStructure *st = NULL; PrivateStream *ps; guint i; GList *tmp; if (!gst_structure_id_has_field (topology, _TOPOLOGY_PAD_QUARK)) { GST_DEBUG ("Could not find pad for node %" GST_PTR_FORMAT "\n", topology); return NULL; } gst_structure_id_get (topology, _TOPOLOGY_PAD_QUARK, GST_TYPE_PAD, &pad, NULL); if (!dc->priv->streams) return NULL; for (i = 0, tmp = dc->priv->streams; tmp; tmp = tmp->next, i++) { ps = (PrivateStream *) tmp->data; target_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (ps->pad)); gst_object_unref (target_pad); if (target_pad == pad) break; } if (tmp) st = collect_stream_information (dc, ps, i); gst_object_unref (pad); return st; }
/* If a parent is non-NULL, collected stream information will be appended to it * (and where the information exists, it will be overriden) */ static GstDiscovererStreamInfo * parse_stream_topology (GstDiscoverer * dc, const GstStructure * topology, GstDiscovererStreamInfo * parent) { GstDiscovererStreamInfo *res = NULL; GstCaps *caps = NULL; const GValue *nval = NULL; GST_DEBUG ("parsing: %" GST_PTR_FORMAT, topology); nval = gst_structure_get_value (topology, "next"); if (nval == NULL || GST_VALUE_HOLDS_STRUCTURE (nval)) { GstStructure *st = find_stream_for_node (dc, topology); gboolean add_to_list = TRUE; if (st) { res = collect_information (dc, st, parent); gst_structure_free (st); } else { /* Didn't find a stream structure, so let's just use the caps we have */ res = collect_information (dc, topology, parent); } if (nval == NULL) { /* FIXME : aggregate with information from main streams */ GST_DEBUG ("Coudn't find 'next' ! might be the last entry"); } else { GstCaps *caps; const GstStructure *st; st = gst_value_get_structure (nval); GST_DEBUG ("next is a structure %" GST_PTR_FORMAT, st); if (!parent) parent = res; if (gst_structure_id_get (st, _CAPS_QUARK, GST_TYPE_CAPS, &caps, NULL)) { if (gst_caps_can_intersect (parent->caps, caps)) { /* 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; 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; } } } if (add_to_list) { dc->priv->current_info->stream_list = g_list_append (dc->priv->current_info->stream_list, res); } } else if (GST_VALUE_HOLDS_LIST (nval)) { guint i, len; GstDiscovererContainerInfo *cont; GstTagList *tags; if (!gst_structure_id_get (topology, _CAPS_QUARK, GST_TYPE_CAPS, &caps, NULL)) GST_WARNING ("Couldn't find caps !"); len = gst_value_list_get_size (nval); GST_DEBUG ("next is a list of %d entries", len); cont = (GstDiscovererContainerInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_CONTAINER_INFO); cont->parent.caps = caps; res = (GstDiscovererStreamInfo *) cont; if (gst_structure_id_has_field (topology, _TAGS_QUARK)) { GstTagList *tmp; gst_structure_id_get (topology, _TAGS_QUARK, GST_TYPE_STRUCTURE, &tags, NULL); GST_DEBUG ("Merge tags %" GST_PTR_FORMAT, tags); tmp = gst_tag_list_merge (cont->parent.tags, (GstTagList *) tags, GST_TAG_MERGE_APPEND); gst_tag_list_free (tags); if (cont->parent.tags) gst_tag_list_free (cont->parent.tags); cont->parent.tags = tmp; GST_DEBUG ("Container info tags %" GST_PTR_FORMAT, tmp); } for (i = 0; i < len; i++) { const GValue *subv = gst_value_list_get_value (nval, i); const GstStructure *subst = gst_value_get_structure (subv); GstDiscovererStreamInfo *substream; GST_DEBUG ("%d %" GST_PTR_FORMAT, i, subst); substream = parse_stream_topology (dc, subst, NULL); substream->previous = res; cont->streams = g_list_append (cont->streams, gst_discoverer_stream_info_ref (substream)); } } return res; }
/* Parses a set of caps and tags in st and populates a GstDiscovererStreamInfo * structure (parent, if !NULL, otherwise it allocates one) */ static GstDiscovererStreamInfo * collect_information (GstDiscoverer * dc, const GstStructure * st, GstDiscovererStreamInfo * parent) { GstCaps *caps; GstStructure *caps_st, *tags_st; const gchar *name; int tmp, tmp2; guint utmp; gboolean btmp; if (!st || !gst_structure_id_has_field (st, _CAPS_QUARK)) { GST_WARNING ("Couldn't find caps !"); if (parent) return parent; else return (GstDiscovererStreamInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_STREAM_INFO); } gst_structure_id_get (st, _CAPS_QUARK, GST_TYPE_CAPS, &caps, NULL); caps_st = gst_caps_get_structure (caps, 0); name = gst_structure_get_name (caps_st); if (g_str_has_prefix (name, "audio/")) { GstDiscovererAudioInfo *info; if (parent) info = (GstDiscovererAudioInfo *) parent; else { info = (GstDiscovererAudioInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO); info->parent.caps = caps; } if (gst_structure_get_int (caps_st, "rate", &tmp)) info->sample_rate = (guint) tmp; if (gst_structure_get_int (caps_st, "channels", &tmp)) info->channels = (guint) tmp; if (gst_structure_get_int (caps_st, "depth", &tmp)) 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)) info->bitrate = utmp; if (gst_structure_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); } return (GstDiscovererStreamInfo *) info; } else if (g_str_has_prefix (name, "video/") || g_str_has_prefix (name, "image/")) { GstDiscovererVideoInfo *info; GstVideoFormat format; if (parent) info = (GstDiscovererVideoInfo *) parent; else { info = (GstDiscovererVideoInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO); info->parent.caps = caps; } if (gst_video_format_parse_caps (caps, &format, &tmp, &tmp2)) { info->width = (guint) tmp; info->height = (guint) tmp2; } if (gst_structure_get_int (caps_st, "depth", &tmp)) info->depth = (guint) tmp; if (gst_video_parse_caps_pixel_aspect_ratio (caps, &tmp, &tmp2)) { info->par_num = tmp; info->par_denom = tmp2; } if (gst_video_parse_caps_framerate (caps, &tmp, &tmp2)) { info->framerate_num = tmp; info->framerate_denom = tmp2; } if (gst_video_format_parse_caps_interlaced (caps, &btmp)) info->interlaced = btmp; 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)) info->bitrate = utmp; if (gst_structure_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); } return (GstDiscovererStreamInfo *) info; } else { /* None of the above - populate what information we can */ GstDiscovererStreamInfo *info; if (parent) info = parent; else { info = (GstDiscovererStreamInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_STREAM_INFO); info->caps = 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); } return info; } }