diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index faf55b97fb..b3134d537a 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -477,6 +477,67 @@ hls_type_find (GstTypeFind * tf, gpointer unused) } \ } +#define XML_INC_BUFFER_DATA { \ + pos++; \ + if (pos >= length) { \ + return FALSE; \ + } else { \ + data++; \ + } \ +} + +static gboolean +xml_check_first_element_from_data (const guint8 * data, guint length, + const gchar * element, guint elen, gboolean strict) +{ + gboolean got_xmldec; + guint pos = 0; + + g_return_val_if_fail (data != NULL, FALSE); + + if (length <= 5) + return FALSE; + + /* look for the XMLDec + * see XML spec 2.8, Prolog and Document Type Declaration + * http://www.w3.org/TR/2004/REC-xml-20040204/#sec-prolog-dtd */ + got_xmldec = (memcmp (data, "= length) + return FALSE; + pos += 5; + data += 5; + } + + /* look for the first element, it has to be the requested element. Bail + * out if it is not within the first 4kB. */ + while (data && pos < MIN (4096, length)) { + while (*data != '<' && pos < MIN (4096, length)) { + XML_INC_BUFFER_DATA; + } + + XML_INC_BUFFER_DATA; + if (!g_ascii_isalpha (*data)) { + /* if not alphabetic, it's a PI or an element / attribute declaration + * like = length) + return FALSE; + return (data && element && strncmp ((char *) data, element, elen) == 0); + } + + return FALSE; +} + static gboolean xml_check_first_element (GstTypeFind * tf, const gchar * element, guint elen, gboolean strict) @@ -3199,6 +3260,64 @@ swf_type_find (GstTypeFind * tf, gpointer unused) } } +/*** application/vnd.ms-sstr+xml ***/ + +static GstStaticCaps mss_manifest_caps = +GST_STATIC_CAPS ("application/vnd.ms-sstr+xml"); +#define MSS_MANIFEST_CAPS (gst_static_caps_get(&mss_manifest_caps)) +static void +mss_manifest_type_find (GstTypeFind * tf, gpointer unused) +{ + if (xml_check_first_element (tf, "SmoothStreamingMedia", 20, TRUE)) { + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MSS_MANIFEST_CAPS); + } else { + const guint8 *data; + gboolean utf16_le, utf16_be; + const gchar *convert_from = NULL; + guint8 *converted_data; + + /* try detecting the charset */ + data = gst_type_find_peek (tf, 0, 2); + + /* look for a possible BOM */ + utf16_le = data[0] == 0xFF && data[1] == 0xFE; + utf16_be = data[0] == 0xFE && data[1] == 0xFF; + if (utf16_le) { + convert_from = "UTF-16LE"; + } else if (utf16_be) { + convert_from = "UTF-16BE"; + } + + if (convert_from) { + gsize new_size = 0; + guint length = gst_type_find_get_length (tf); + + /* try a default that should be enough */ + if (length == 0) + length = 512; + data = gst_type_find_peek (tf, 0, length); + + if (data) { + /* skip the BOM */ + data += 2; + length -= 2; + + converted_data = + (guint8 *) g_convert ((gchar *) data, length, "UTF-8", convert_from, + NULL, &new_size, NULL); + if (converted_data) { + if (xml_check_first_element_from_data (converted_data, new_size, + "SmoothStreamingMedia", 20, TRUE)) + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, + MSS_MANIFEST_CAPS); + + g_free (converted_data); + } + } + } + } +} + /*** image/jpeg ***/ #define JPEG_MARKER_IS_START_OF_FRAME(x) \ @@ -5058,6 +5177,9 @@ plugin_init (GstPlugin * plugin) GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "application/x-shockwave-flash", GST_RANK_SECONDARY, swf_type_find, "swf,swfl", SWF_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "application/vnd.ms-sstr+xml", + GST_RANK_PRIMARY, mss_manifest_type_find, NULL, MSS_MANIFEST_CAPS, NULL, + NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-flv", GST_RANK_SECONDARY, "flv", "FLV", 3, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "text/plain", GST_RANK_MARGINAL, utf8_type_find,