2013-05-08 14:13:32 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2012-10-17 13:50:33 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2013-05-08 14:13:32 +00:00
|
|
|
#include <gst/gst.h>
|
|
|
|
|
|
|
|
#include "gstdashdemux.h"
|
|
|
|
|
|
|
|
GST_DEBUG_CATEGORY (fragmented_debug);
|
|
|
|
|
2012-10-17 13:50:33 +00:00
|
|
|
#define XML_BUFFER_SIZE 16
|
|
|
|
#define XML_INC_BUFFER { \
|
|
|
|
pos++; \
|
|
|
|
if (pos == XML_BUFFER_SIZE) { \
|
|
|
|
pos = 0; \
|
|
|
|
offset += XML_BUFFER_SIZE; \
|
|
|
|
data = gst_type_find_peek (tf, offset, XML_BUFFER_SIZE); \
|
|
|
|
if (data == NULL) return FALSE; \
|
|
|
|
} else { \
|
|
|
|
data++; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xml_check_first_element (GstTypeFind * tf, const gchar * element, guint elen,
|
|
|
|
gboolean strict)
|
|
|
|
{
|
|
|
|
gboolean got_xmldec;
|
|
|
|
const guint8 *data;
|
|
|
|
guint offset = 0;
|
|
|
|
guint pos = 0;
|
|
|
|
|
|
|
|
data = gst_type_find_peek (tf, 0, XML_BUFFER_SIZE);
|
|
|
|
if (!data)
|
|
|
|
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, "<?xml", 5) == 0);
|
|
|
|
|
|
|
|
if (strict && !got_xmldec)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* skip XMLDec in any case if we've got one */
|
|
|
|
if (got_xmldec) {
|
|
|
|
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 && (offset + pos) < 4096) {
|
|
|
|
while (*data != '<' && (offset + pos) < 4096) {
|
|
|
|
XML_INC_BUFFER;
|
|
|
|
}
|
|
|
|
|
|
|
|
XML_INC_BUFFER;
|
|
|
|
if (!g_ascii_isalpha (*data)) {
|
|
|
|
/* if not alphabetic, it's a PI or an element / attribute declaration
|
|
|
|
* like <?xxx or <!xxx */
|
|
|
|
XML_INC_BUFFER;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the first normal element, check if it's the one asked for */
|
|
|
|
data = gst_type_find_peek (tf, offset + pos, elen + 1);
|
|
|
|
return (data && element && strncmp ((char *) data, element, elen) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*** application/dash+xml typefind helper ***/
|
|
|
|
|
|
|
|
static GstStaticCaps dash_caps = GST_STATIC_CAPS ("application/dash+xml");
|
|
|
|
|
|
|
|
#define DASH_CAPS gst_static_caps_get (&dash_caps)
|
|
|
|
|
|
|
|
static void
|
|
|
|
dash_type_find (GstTypeFind * tf, gpointer unused)
|
|
|
|
{
|
|
|
|
if (xml_check_first_element (tf, "MPD", 3, FALSE) ||
|
|
|
|
xml_check_first_element (tf, "mpd", 3, FALSE)) {
|
|
|
|
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, DASH_CAPS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:13:32 +00:00
|
|
|
static gboolean
|
|
|
|
fragmented_init (GstPlugin * plugin)
|
|
|
|
{
|
|
|
|
GST_DEBUG_CATEGORY_INIT (fragmented_debug, "dashdemux", 0, "dashdemux");
|
|
|
|
if (!gst_element_register (plugin, "dashdemux", GST_RANK_PRIMARY,
|
|
|
|
GST_TYPE_DASH_DEMUX) || FALSE)
|
|
|
|
return FALSE;
|
2012-10-17 13:50:33 +00:00
|
|
|
gst_type_find_register (plugin, "application/dash+xml",
|
|
|
|
GST_RANK_SECONDARY, dash_type_find, NULL, DASH_CAPS, NULL, NULL);
|
2013-05-08 14:13:32 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
|
|
|
GST_VERSION_MINOR,
|
2013-04-18 10:41:09 +00:00
|
|
|
dashdemux,
|
2012-11-12 09:54:35 +00:00
|
|
|
"DASH demuxer plugin",
|
2013-05-08 14:13:32 +00:00
|
|
|
fragmented_init, VERSION, "LGPL", PACKAGE_NAME, "http://www.gstreamer.org/")
|