summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeungha Yang <sh.yang@lge.com>2016-11-14 23:31:37 +0900
committerSebastian Dröge <sebastian@centricular.com>2016-11-14 16:56:43 +0200
commit68e4f919a004937f1a35be35a447d4de55f612b9 (patch)
treec8d4d2a2371edecf8cbdb40cebc3bcaf82db4f3a
parent71df82db63ff9a780162d9e8eea985b2172021e0 (diff)
mpdparser: Support multiple Period elements in external xml
External xml could have empty, one or multiple top-level "Period" elements. Because xml parser cannot parse the multiple top-level elements (i.e., no root element), we need to wrap a xml in order to make root element. See also ISO/IEC 23009-1:2014 5.3.2.2 https://bugzilla.gnome.org/show_bug.cgi?id=774357
-rw-r--r--ext/dash/gstmpdparser.c69
-rw-r--r--ext/dash/gstmpdparser.h1
-rw-r--r--tests/check/Makefile.am5
-rw-r--r--tests/check/elements/dash_mpd.c104
-rw-r--r--tests/check/elements/dash_mpd_data/xlink_double_period.period2
-rw-r--r--tests/check/elements/dash_mpd_data/xlink_single_period.period1
6 files changed, 163 insertions, 19 deletions
diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c
index 1e757bd59..6ab8032eb 100644
--- a/ext/dash/gstmpdparser.c
+++ b/ext/dash/gstmpdparser.c
@@ -4186,19 +4186,23 @@ gst_mpd_client_setup_representation (GstMpdClient * client,
return TRUE;
}
+#define CUSTOM_WRAPPER_START "<custom_wrapper>"
+#define CUSTOM_WRAPPER_END "</custom_wrapper>"
+
static GList *
gst_mpd_client_fetch_external_period (GstMpdClient * client,
GstPeriodNode * period_node, gboolean * error)
{
GstFragment *download;
+ GstAdapter *adapter;
GstBuffer *period_buffer;
- GstMapInfo map;
GError *err = NULL;
xmlDocPtr doc;
GstUri *base_uri, *uri;
gchar *query = NULL;
- gchar *uri_string;
+ gchar *uri_string, *wrapper;
GList *new_periods = NULL;
+ const gchar *data;
*error = FALSE;
@@ -4248,34 +4252,65 @@ gst_mpd_client_fetch_external_period (GstMpdClient * client,
period_buffer = gst_fragment_get_buffer (download);
g_object_unref (download);
- gst_buffer_map (period_buffer, &map, GST_MAP_READ);
+ /* external xml could have multiple period without root xmlNode.
+ * To avoid xml parsing error caused by no root node, wrapping it with
+ * custom root node */
+ adapter = gst_adapter_new ();
+
+ wrapper = g_new (gchar, strlen (CUSTOM_WRAPPER_START));
+ memcpy (wrapper, CUSTOM_WRAPPER_START, strlen (CUSTOM_WRAPPER_START));
+ gst_adapter_push (adapter,
+ gst_buffer_new_wrapped (wrapper, strlen (CUSTOM_WRAPPER_START)));
+
+ gst_adapter_push (adapter, period_buffer);
+
+ wrapper = g_strdup (CUSTOM_WRAPPER_END);
+ gst_adapter_push (adapter,
+ gst_buffer_new_wrapped (wrapper, strlen (CUSTOM_WRAPPER_END) + 1));
+
+ data = gst_adapter_map (adapter, gst_adapter_available (adapter));
doc =
- xmlReadMemory ((const gchar *) map.data, map.size, "noname.xml", NULL,
+ xmlReadMemory (data, gst_adapter_available (adapter), "noname.xml", NULL,
XML_PARSE_NONET);
if (doc) {
xmlNode *root_element = xmlDocGetRootElement (doc);
- if (root_element->type != XML_ELEMENT_NODE ||
- xmlStrcmp (root_element->name, (xmlChar *) "Period") != 0) {
- xmlFreeDoc (doc);
- gst_buffer_unmap (period_buffer, &map);
- gst_buffer_unref (period_buffer);
- *error = TRUE;
- return NULL;
- }
+ xmlNode *iter;
+
+ if (root_element->type != XML_ELEMENT_NODE)
+ goto error;
- gst_mpdparser_parse_period_node (&new_periods, root_element);
+ for (iter = root_element->children; iter; iter = iter->next) {
+ if (iter->type == XML_ELEMENT_NODE) {
+ if (xmlStrcmp (iter->name, (xmlChar *) "Period") == 0) {
+ gst_mpdparser_parse_period_node (&new_periods, iter);
+ } else {
+ goto error;
+ }
+ }
+ }
} else {
GST_ERROR ("Failed to parse period node XML");
- gst_buffer_unmap (period_buffer, &map);
- gst_buffer_unref (period_buffer);
+ gst_adapter_unmap (adapter);
+ gst_adapter_clear (adapter);
+ gst_object_unref (adapter);
*error = TRUE;
return NULL;
}
- gst_buffer_unmap (period_buffer, &map);
- gst_buffer_unref (period_buffer);
+ xmlFreeDoc (doc);
+ gst_adapter_unmap (adapter);
+ gst_adapter_clear (adapter);
+ gst_object_unref (adapter);
return new_periods;
+
+error:
+ xmlFreeDoc (doc);
+ gst_adapter_unmap (adapter);
+ gst_adapter_clear (adapter);
+ gst_object_unref (adapter);
+ *error = TRUE;
+ return NULL;
}
gboolean
diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h
index 85b97ea2a..04b935e3a 100644
--- a/ext/dash/gstmpdparser.h
+++ b/ext/dash/gstmpdparser.h
@@ -29,6 +29,7 @@
#include <gst/gst.h>
#include <gst/uridownloader/gsturidownloader.h>
+#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index 35a4a251d..90b216520 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -470,8 +470,9 @@ elements_mpegtsmux_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_VIDEO_LIBS) $(GST_BASE
elements_uvch264demux_CFLAGS = -DUVCH264DEMUX_DATADIR="$(srcdir)/elements/uvch264demux_data" \
$(AM_CFLAGS)
-elements_dash_mpd_CFLAGS = $(AM_CFLAGS) $(GST_PLUGINS_BAD_CFLAGS) $(LIBXML2_CFLAGS)
-elements_dash_mpd_LDADD = $(LDADD) $(LIBXML2_LIBS) \
+elements_dash_mpd_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) $(GST_PLUGINS_BAD_CFLAGS) $(LIBXML2_CFLAGS) \
+ -DDASH_MPD_DATADIR="$(srcdir)/elements/dash_mpd_data"
+elements_dash_mpd_LDADD = $(GST_BASE_LIBS) $(LDADD) $(LIBXML2_LIBS) \
$(top_builddir)/gst-libs/gst/uridownloader/libgsturidownloader-@GST_API_VERSION@.la
elements_dash_mpd_SOURCES = elements/dash_mpd.c
diff --git a/tests/check/elements/dash_mpd.c b/tests/check/elements/dash_mpd.c
index 5585f4980..946921217 100644
--- a/tests/check/elements/dash_mpd.c
+++ b/tests/check/elements/dash_mpd.c
@@ -5529,6 +5529,107 @@ GST_START_TEST (dash_mpdparser_maximum_segment_duration)
GST_END_TEST;
/*
+ * Test parsing of Perioud using @xlink:href attribute
+ */
+
+#define STRINGIFY_(x) #x
+#define STRINGIFY(x) STRINGIFY_ (x)
+#define REMOTEDIR STRINGIFY (DASH_MPD_DATADIR)
+#define XLINK_SINGLE_PERIOD_FILENAME REMOTEDIR "/xlink_single_period.period"
+#define XLINK_DOUBLE_PERIOD_FILENAME REMOTEDIR "/xlink_double_period.period"
+
+GST_START_TEST (dash_mpdparser_xlink_period)
+{
+ GstPeriodNode *periodNode;
+ GstUriDownloader *downloader;
+ GstMpdClient *mpdclient;
+ GList *period_list, *iter;
+ gboolean ret;
+ gchar *xml_joined, *file_uri_single_period, *file_uri_double_period;
+ const gchar *xml_frag_start =
+ "<?xml version=\"1.0\"?>"
+ "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
+ " profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
+ " <Period id=\"Period0\"" "duration=\"PT5S\"></Period>";
+
+ const gchar *xml_uri_front = " <Period xlink:href=\"";
+
+ const gchar *xml_uri_rear =
+ "\""
+ " xlink:actuate=\"onRequest\""
+ " xmlns:xlink=\"http://www.w3.org/1999/xlink\"></Period>";
+
+ const gchar *xml_frag_end = "</MPD>";
+
+ /* XLINK_ONE_PERIOD_FILENAME
+ *
+ * <Period id="xlink-single-period-Period1" duration="PT10S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
+ */
+
+ /* XLINK_TWO_PERIODS_FILENAME
+ *
+ * <Period id="xlink-double-period-Period1" duration="PT10S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
+ * <Period id="xlink-double-period-Period2" duration="PT20S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
+ */
+
+
+ mpdclient = gst_mpd_client_new ();
+ downloader = gst_uri_downloader_new ();
+
+ gst_mpd_client_set_uri_downloader (mpdclient, downloader);
+
+ file_uri_single_period =
+ gst_filename_to_uri (XLINK_SINGLE_PERIOD_FILENAME, NULL);
+ file_uri_double_period =
+ gst_filename_to_uri (XLINK_DOUBLE_PERIOD_FILENAME, NULL);
+
+ /* constructs inital mpd using external xml uri */
+ xml_joined = g_strjoin ("", xml_frag_start,
+ xml_uri_front, (const char *) file_uri_single_period, xml_uri_rear,
+ xml_uri_front, (const char *) file_uri_double_period, xml_uri_rear,
+ xml_frag_end, NULL);
+
+ ret = gst_mpd_parse (mpdclient, xml_joined, (gint) strlen (xml_joined));
+ assert_equals_int (ret, TRUE);
+
+ period_list = mpdclient->mpd_node->Periods;
+ /* only count periods on initial mpd (external xml does not parsed yet) */
+ assert_equals_int (g_list_length (period_list), 3);
+
+ /* process the xml data */
+ ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
+ -1, NULL);
+ assert_equals_int (ret, TRUE);
+
+ period_list = mpdclient->mpd_node->Periods;
+ assert_equals_int (g_list_length (period_list), 4);
+
+ iter = period_list;
+ periodNode = (GstPeriodNode *) iter->data;
+ assert_equals_string (periodNode->id, "Period0");
+
+ iter = iter->next;
+ periodNode = (GstPeriodNode *) iter->data;
+ assert_equals_string (periodNode->id, "xlink-single-period-Period1");
+
+ iter = iter->next;
+ periodNode = (GstPeriodNode *) iter->data;
+ assert_equals_string (periodNode->id, "xlink-double-period-Period1");
+
+ iter = iter->next;
+ periodNode = (GstPeriodNode *) iter->data;
+ assert_equals_string (periodNode->id, "xlink-double-period-Period2");
+
+ gst_mpd_client_free (mpdclient);
+ g_object_unref (downloader);
+ g_free (file_uri_single_period);
+ g_free (file_uri_double_period);
+ g_free (xml_joined);
+}
+
+GST_END_TEST;
+
+/*
* create a test suite containing all dash testcases
*/
static Suite *
@@ -5654,6 +5755,9 @@ dash_suite (void)
tcase_add_test (tc_simpleMPD, dash_mpdparser_various_duration_formats);
tcase_add_test (tc_simpleMPD, dash_mpdparser_default_presentation_delay);
+ /* tests checking xlink attributes */
+ tcase_add_test (tc_simpleMPD, dash_mpdparser_xlink_period);
+
/* tests checking the MPD management
* (eg. setting active streams, obtaining attributes values)
*/
diff --git a/tests/check/elements/dash_mpd_data/xlink_double_period.period b/tests/check/elements/dash_mpd_data/xlink_double_period.period
new file mode 100644
index 000000000..cb656b953
--- /dev/null
+++ b/tests/check/elements/dash_mpd_data/xlink_double_period.period
@@ -0,0 +1,2 @@
+<Period id="xlink-double-period-Period1" duration="PT10S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
+<Period id="xlink-double-period-Period2" duration="PT20S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>
diff --git a/tests/check/elements/dash_mpd_data/xlink_single_period.period b/tests/check/elements/dash_mpd_data/xlink_single_period.period
new file mode 100644
index 000000000..dd85543af
--- /dev/null
+++ b/tests/check/elements/dash_mpd_data/xlink_single_period.period
@@ -0,0 +1 @@
+<Period id="xlink-single-period-Period1" duration="PT10S" xmlns="urn:mpeg:dash:schema:mpd:2011"></Period>