gstreamer/subprojects/gst-plugins-bad/tests/check/elements/dash_mpd.c

6732 lines
245 KiB
C
Raw Normal View History

/* GStreamer unit test for MPEG-DASH
*
* Copyright (c) <2015> YouView TV Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "../../ext/dash/gstmpdparser.c"
#include "../../ext/dash/gstxmlhelper.c"
#include "../../ext/dash/gstmpdhelper.c"
#include "../../ext/dash/gstmpdnode.c"
#include "../../ext/dash/gstmpdrepresentationbasenode.c"
#include "../../ext/dash/gstmpdmultsegmentbasenode.c"
#include "../../ext/dash/gstmpdrootnode.c"
#include "../../ext/dash/gstmpdbaseurlnode.c"
#include "../../ext/dash/gstmpdutctimingnode.c"
#include "../../ext/dash/gstmpdmetricsnode.c"
#include "../../ext/dash/gstmpdmetricsrangenode.c"
#include "../../ext/dash/gstmpdsnode.c"
#include "../../ext/dash/gstmpdsegmenttimelinenode.c"
#include "../../ext/dash/gstmpdsegmenttemplatenode.c"
#include "../../ext/dash/gstmpdsegmenturlnode.c"
#include "../../ext/dash/gstmpdsegmentlistnode.c"
#include "../../ext/dash/gstmpdsegmentbasenode.c"
#include "../../ext/dash/gstmpdperiodnode.c"
#include "../../ext/dash/gstmpdsubrepresentationnode.c"
#include "../../ext/dash/gstmpdrepresentationnode.c"
#include "../../ext/dash/gstmpdcontentcomponentnode.c"
#include "../../ext/dash/gstmpdadaptationsetnode.c"
#include "../../ext/dash/gstmpdsubsetnode.c"
#include "../../ext/dash/gstmpdprograminformationnode.c"
#include "../../ext/dash/gstmpdlocationnode.c"
#include "../../ext/dash/gstmpdreportingnode.c"
#include "../../ext/dash/gstmpdurltypenode.c"
#include "../../ext/dash/gstmpddescriptortypenode.c"
#include "../../ext/dash/gstmpdclient.c"
#undef GST_CAT_DEFAULT
#include <gst/check/gstcheck.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
GST_DEBUG_CATEGORY (gst_dash_demux_debug);
/*
* compute the number of milliseconds contained in a duration value specified by
* year, month, day, hour, minute, second, millisecond
*
* This function must use the same conversion algorithm implemented in
* gst_xml_helper_get_prop_duration from gstmpdparser.c file.
*/
static guint64
duration_to_ms (guint year, guint month, guint day, guint hour, guint minute,
guint second, guint millisecond)
{
guint64 days = (guint64) year * 365 + (guint64) month * 30 + day;
guint64 hours = days * 24 + hour;
guint64 minutes = hours * 60 + minute;
guint64 seconds = minutes * 60 + second;
guint64 ms = seconds * 1000 + millisecond;
return ms;
}
static GstClockTime
duration_to_clocktime (guint year, guint month, guint day, guint hour,
guint minute, guint second, guint millisecond)
{
return (GST_MSECOND * duration_to_ms (year, month, day, hour, minute, second,
millisecond));
}
/*
* Test to ensure a simple mpd file successfully parses.
*
*/
GST_START_TEST (dash_mpdparser_validsimplempd)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"> </MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* check that unset elements with default values are properly configured */
assert_equals_int (mpdclient->mpd_root_node->type, GST_MPD_FILE_TYPE_STATIC);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing the MPD attributes.
*
*/
GST_START_TEST (dash_mpdparser_mpd)
{
GstDateTime *availabilityStartTime;
GstDateTime *availabilityEndTime;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" schemaLocation=\"TestSchemaLocation\""
" xmlns:xsi=\"TestNamespaceXSI\""
" xmlns:ext=\"TestNamespaceEXT\""
" id=\"testId\""
" type=\"static\""
" availabilityStartTime=\"2015-03-24T1:10:50\""
" availabilityEndTime=\"2015-03-24T1:10:50.123456\""
" mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
" minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
" minBufferTime=\"P0Y1M2DT12H10M20.5S\""
" timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
" suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
" maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
" maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\"></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
assert_equals_string (mpdclient->mpd_root_node->default_namespace,
"urn:mpeg:dash:schema:mpd:2011");
assert_equals_string (mpdclient->mpd_root_node->namespace_xsi,
"TestNamespaceXSI");
assert_equals_string (mpdclient->mpd_root_node->namespace_ext,
"TestNamespaceEXT");
assert_equals_string (mpdclient->mpd_root_node->schemaLocation,
"TestSchemaLocation");
assert_equals_string (mpdclient->mpd_root_node->id, "testId");
assert_equals_int (mpdclient->mpd_root_node->type, GST_MPD_FILE_TYPE_STATIC);
availabilityStartTime = mpdclient->mpd_root_node->availabilityStartTime;
assert_equals_int (gst_date_time_get_year (availabilityStartTime), 2015);
assert_equals_int (gst_date_time_get_month (availabilityStartTime), 3);
assert_equals_int (gst_date_time_get_day (availabilityStartTime), 24);
assert_equals_int (gst_date_time_get_hour (availabilityStartTime), 1);
assert_equals_int (gst_date_time_get_minute (availabilityStartTime), 10);
assert_equals_int (gst_date_time_get_second (availabilityStartTime), 50);
assert_equals_int (gst_date_time_get_microsecond (availabilityStartTime), 0);
availabilityEndTime = mpdclient->mpd_root_node->availabilityEndTime;
assert_equals_int (gst_date_time_get_year (availabilityEndTime), 2015);
assert_equals_int (gst_date_time_get_month (availabilityEndTime), 3);
assert_equals_int (gst_date_time_get_day (availabilityEndTime), 24);
assert_equals_int (gst_date_time_get_hour (availabilityEndTime), 1);
assert_equals_int (gst_date_time_get_minute (availabilityEndTime), 10);
assert_equals_int (gst_date_time_get_second (availabilityEndTime), 50);
assert_equals_int (gst_date_time_get_microsecond (availabilityEndTime),
123456);
assert_equals_uint64 (mpdclient->mpd_root_node->mediaPresentationDuration,
duration_to_ms (0, 1, 2, 12, 10, 20, 500));
assert_equals_uint64 (mpdclient->mpd_root_node->minimumUpdatePeriod,
duration_to_ms (0, 1, 2, 12, 10, 20, 500));
assert_equals_uint64 (mpdclient->mpd_root_node->minBufferTime,
duration_to_ms (0, 1, 2, 12, 10, 20, 500));
assert_equals_uint64 (mpdclient->mpd_root_node->timeShiftBufferDepth,
duration_to_ms (0, 1, 2, 12, 10, 20, 500));
assert_equals_uint64 (mpdclient->mpd_root_node->suggestedPresentationDelay,
duration_to_ms (0, 1, 2, 12, 10, 20, 500));
assert_equals_uint64 (mpdclient->mpd_root_node->maxSegmentDuration,
duration_to_ms (0, 1, 2, 12, 10, 20, 500));
assert_equals_uint64 (mpdclient->mpd_root_node->maxSubsegmentDuration,
duration_to_ms (0, 1, 2, 12, 10, 20, 500));
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing the ProgramInformation attributes
*
*/
GST_START_TEST (dash_mpdparser_programInformation)
{
GstMPDProgramInformationNode *program;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <ProgramInformation lang=\"en\""
" moreInformationURL=\"TestMoreInformationUrl\">"
" <Title>TestTitle</Title>"
" <Source>TestSource</Source>"
" <Copyright>TestCopyright</Copyright>"
" </ProgramInformation> </MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
program =
(GstMPDProgramInformationNode *) mpdclient->mpd_root_node->ProgramInfos->
data;
assert_equals_string (program->lang, "en");
assert_equals_string (program->moreInformationURL, "TestMoreInformationUrl");
assert_equals_string (program->Title, "TestTitle");
assert_equals_string (program->Source, "TestSource");
assert_equals_string (program->Copyright, "TestCopyright");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing the BaseURL attributes
*
*/
GST_START_TEST (dash_mpdparser_baseURL)
{
GstMPDBaseURLNode *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL serviceLocation=\"TestServiceLocation\""
" byteRange=\"TestByteRange\">TestBaseURL</BaseURL></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
baseURL = (GstMPDBaseURLNode *) mpdclient->mpd_root_node->BaseURLs->data;
assert_equals_string (baseURL->baseURL, "TestBaseURL");
assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
assert_equals_string (baseURL->byteRange, "TestByteRange");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing the Location attributes
*
*/
GST_START_TEST (dash_mpdparser_location)
{
GstMPDLocationNode *location;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Location>TestLocation</Location></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
location = (GstMPDLocationNode *) mpdclient->mpd_root_node->Locations->data;
assert_equals_string (location->location, "TestLocation");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Metrics attributes
*
*/
GST_START_TEST (dash_mpdparser_metrics)
{
GstMPDMetricsNode *metricsNode;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Metrics metrics=\"TestMetric\"></Metrics></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
metricsNode = (GstMPDMetricsNode *) mpdclient->mpd_root_node->Metrics->data;
assert_equals_string (metricsNode->metrics, "TestMetric");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Metrics Range attributes
*
*/
GST_START_TEST (dash_mpdparser_metrics_range)
{
GstMPDMetricsNode *metricsNode;
GstMPDMetricsRangeNode *metricsRangeNode;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Metrics>"
" <Range starttime=\"P0Y1M2DT12H10M20.5S\""
" duration=\"P0Y1M2DT12H10M20.1234567S\">"
" </Range></Metrics></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
metricsNode = (GstMPDMetricsNode *) mpdclient->mpd_root_node->Metrics->data;
assert_equals_pointer (metricsNode->metrics, NULL);
metricsRangeNode =
(GstMPDMetricsRangeNode *) metricsNode->MetricsRanges->data;
assert_equals_uint64 (metricsRangeNode->starttime, duration_to_ms (0, 1, 2,
12, 10, 20, 500));
assert_equals_uint64 (metricsRangeNode->duration, duration_to_ms (0, 1, 2, 12,
10, 20, 123));
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Metrics Reporting attributes
*
*/
GST_START_TEST (dash_mpdparser_metrics_reporting)
{
GstMPDMetricsNode *metricsNode;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Metrics><Reporting></Reporting></Metrics></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
metricsNode = (GstMPDMetricsNode *) mpdclient->mpd_root_node->Metrics->data;
assert_equals_pointer (metricsNode->metrics, NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period attributes
*
*/
GST_START_TEST (dash_mpdparser_period)
{
GstMPDPeriodNode *periodNode;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"TestId\""
" start=\"P0Y1M2DT12H10M20.1234567S\""
" duration=\"P0Y1M2DT12H10M20.7654321S\""
" bitstreamSwitching=\"true\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
assert_equals_string (periodNode->id, "TestId");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 1, 2, 12, 10, 20, 123));
assert_equals_uint64 (periodNode->duration,
duration_to_ms (0, 1, 2, 12, 10, 20, 765));
assert_equals_int (periodNode->bitstreamSwitching, 1);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period baseURL attributes
*
*/
GST_START_TEST (dash_mpdparser_period_baseURL)
{
GstMPDPeriodNode *periodNode;
GstMPDBaseURLNode *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <BaseURL serviceLocation=\"TestServiceLocation\""
" byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
" </Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
baseURL = (GstMPDBaseURLNode *) periodNode->BaseURLs->data;
assert_equals_string (baseURL->baseURL, "TestBaseURL");
assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
assert_equals_string (baseURL->byteRange, "TestByteRange");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentBase attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentBase)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentBaseNode *segmentBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentBase timescale=\"123456\""
" presentationTimeOffset=\"123456789\""
" indexRange=\"100-200\""
" indexRangeExact=\"true\">"
" </SegmentBase></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentBase = periodNode->SegmentBase;
assert_equals_uint64 (segmentBase->timescale, 123456);
assert_equals_uint64 (segmentBase->presentationTimeOffset, 123456789);
assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 100);
assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 200);
assert_equals_int (segmentBase->indexRangeExact, 1);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentBase Initialization attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentBase_initialization)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentBaseNode *segmentBase;
GstMPDURLTypeNode *initialization;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentBase>"
" <Initialisation sourceURL=\"TestSourceURL\""
" range=\"100-200\">"
" </Initialisation></SegmentBase></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentBase = periodNode->SegmentBase;
initialization = segmentBase->Initialization;
assert_equals_string (initialization->sourceURL, "TestSourceURL");
assert_equals_uint64 (initialization->range->first_byte_pos, 100);
assert_equals_uint64 (initialization->range->last_byte_pos, 200);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentBase RepresentationIndex attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentBase_representationIndex)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentBaseNode *segmentBase;
GstMPDURLTypeNode *representationIndex;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentBase>"
" <RepresentationIndex sourceURL=\"TestSourceURL\""
" range=\"100-200\">"
" </RepresentationIndex></SegmentBase></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentBase = periodNode->SegmentBase;
representationIndex = segmentBase->RepresentationIndex;
assert_equals_string (representationIndex->sourceURL, "TestSourceURL");
assert_equals_uint64 (representationIndex->range->first_byte_pos, 100);
assert_equals_uint64 (representationIndex->range->last_byte_pos, 200);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentList attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentList)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentListNode *segmentList;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period><SegmentList duration=\"1\"></SegmentList></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentList = periodNode->SegmentList;
fail_if (segmentList == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentList MultipleSegmentBaseType attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentList_multipleSegmentBaseType)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentListNode *segmentList;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentList duration=\"10\""
" startNumber=\"11\">"
" </SegmentList></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentList = periodNode->SegmentList;
assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->duration,
10);
assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
(segmentList)->startNumber, 11);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentList MultipleSegmentBaseType SegmentBaseType
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentBaseType)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentListNode *segmentList;
GstMPDSegmentBaseNode *segmentBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentList timescale=\"10\""
" duration=\"1\""
" presentationTimeOffset=\"11\""
" indexRange=\"20-21\""
" indexRangeExact=\"false\">"
" </SegmentList></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentList = periodNode->SegmentList;
segmentBase = GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->SegmentBase;
assert_equals_uint64 (segmentBase->timescale, 10);
assert_equals_uint64 (segmentBase->presentationTimeOffset, 11);
assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 20);
assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 21);
assert_equals_int (segmentBase->indexRangeExact, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentList MultipleSegmentBaseType SegmentTimeline
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentListNode *segmentList;
GstMPDSegmentTimelineNode *segmentTimeline;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentList>"
" <SegmentTimeline>"
" </SegmentTimeline></SegmentList></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentList = periodNode->SegmentList;
segmentTimeline =
GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->SegmentTimeline;
fail_if (segmentTimeline == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentList MultipleSegmentBaseType SegmentTimeline S
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline_s)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentListNode *segmentList;
GstMPDSegmentTimelineNode *segmentTimeline;
GstMPDSNode *sNode;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentList>"
" <SegmentTimeline>"
" <S t=\"1\" d=\"2\" r=\"3\">"
" </S></SegmentTimeline></SegmentList></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentList = periodNode->SegmentList;
segmentTimeline =
GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->SegmentTimeline;
sNode = (GstMPDSNode *) g_queue_peek_head (&segmentTimeline->S);
assert_equals_uint64 (sNode->t, 1);
assert_equals_uint64 (sNode->d, 2);
assert_equals_uint64 (sNode->r, 3);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentList MultipleSegmentBaseType BitstreamSwitching
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentList_multipleSegmentBaseType_bitstreamSwitching)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentListNode *segmentList;
GstMPDURLTypeNode *bitstreamSwitching;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentList duration=\"0\">"
" <BitstreamSwitching sourceURL=\"TestSourceURL\""
" range=\"100-200\">"
" </BitstreamSwitching></SegmentList></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentList = periodNode->SegmentList;
bitstreamSwitching =
GST_MPD_MULT_SEGMENT_BASE_NODE (segmentList)->BitstreamSwitching;
assert_equals_string (bitstreamSwitching->sourceURL, "TestSourceURL");
assert_equals_uint64 (bitstreamSwitching->range->first_byte_pos, 100);
assert_equals_uint64 (bitstreamSwitching->range->last_byte_pos, 200);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentList SegmentURL attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentList_segmentURL)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentListNode *segmentList;
GstMPDSegmentURLNode *segmentURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentList duration=\"1\">"
" <SegmentURL media=\"TestMedia\""
" mediaRange=\"100-200\""
" index=\"TestIndex\""
" indexRange=\"300-400\">"
" </SegmentURL></SegmentList></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentList = periodNode->SegmentList;
segmentURL = (GstMPDSegmentURLNode *) segmentList->SegmentURL->data;
assert_equals_string (segmentURL->media, "TestMedia");
assert_equals_uint64 (segmentURL->mediaRange->first_byte_pos, 100);
assert_equals_uint64 (segmentURL->mediaRange->last_byte_pos, 200);
assert_equals_string (segmentURL->index, "TestIndex");
assert_equals_uint64 (segmentURL->indexRange->first_byte_pos, 300);
assert_equals_uint64 (segmentURL->indexRange->last_byte_pos, 400);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentTemplate attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentTemplate)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentTemplateNode *segmentTemplate;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate media=\"TestMedia\""
" duration=\"0\""
" index=\"TestIndex\""
" initialization=\"TestInitialization\""
" bitstreamSwitching=\"TestBitstreamSwitching\">"
" </SegmentTemplate></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentTemplate = periodNode->SegmentTemplate;
assert_equals_string (segmentTemplate->media, "TestMedia");
assert_equals_string (segmentTemplate->index, "TestIndex");
assert_equals_string (segmentTemplate->initialization, "TestInitialization");
assert_equals_string (segmentTemplate->bitstreamSwitching,
"TestBitstreamSwitching");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentTemplate attributes where a
* presentationTimeOffset attribute has been specified
*
*/
GST_START_TEST (dash_mpdparser_period_segmentTemplateWithPresentationTimeOffset)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period start=\"PT1M\" duration=\"PT40S\">"
" <AdaptationSet"
" bitstreamSwitching=\"false\""
" mimeType=\"video/mp4\""
" contentType=\"video\">"
" <SegmentTemplate media=\"$RepresentationID$/TestMedia-$Time$.mp4\""
" index=\"$RepresentationID$/TestIndex.mp4\""
" timescale=\"100\""
" presentationTimeOffset=\"6000\""
" initialization=\"$RepresentationID$/TestInitialization\""
" bitstreamSwitching=\"true\">"
" <SegmentTimeline>"
" <S d=\"400\" r=\"9\" t=\"100\"/>"
" </SegmentTimeline></SegmentTemplate>"
" <Representation bandwidth=\"95866\" frameRate=\"90000/3600\""
" id=\"vrep\" /></AdaptationSet></Period></MPD>";
gboolean ret;
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstActiveStream *activeStream;
GstMediaFragmentInfo fragment;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
GstMPDClient *mpdclient;
GstMPDPeriodNode *periodNode;
GstMPDSegmentTemplateNode *segmentTemplate;
mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
0);
fail_if (periodNode == NULL);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
segmentTemplate = adapt_set->SegmentTemplate;
fail_if (segmentTemplate == NULL);
assert_equals_string (segmentTemplate->media,
"$RepresentationID$/TestMedia-$Time$.mp4");
assert_equals_string (segmentTemplate->index,
"$RepresentationID$/TestIndex.mp4");
assert_equals_string (segmentTemplate->initialization,
"$RepresentationID$/TestInitialization");
assert_equals_string (segmentTemplate->bitstreamSwitching, "true");
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 4, 0);
/* start = Period@start + S@t - presentationTimeOffset */
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 1, 0);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
/* the $Time$ expansion uses the @t value, without including
Period@start or presentationTimeOffset */
assert_equals_string (fragment.uri, "/vrep/TestMedia-100.mp4");
gst_mpdparser_media_fragment_info_clear (&fragment);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentTemplate MultipleSegmentBaseType attributes
*
*/
GST_START_TEST (dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentTemplateNode *segmentTemplate;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate duration=\"10\""
" startNumber=\"11\">"
" </SegmentTemplate></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentTemplate = periodNode->SegmentTemplate;
assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
(segmentTemplate)->duration, 10);
assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
(segmentTemplate)->startNumber, 11);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentTemplate MultipleSegmentBaseType SegmentBaseType
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentBaseType)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentTemplateNode *segmentTemplate;
GstMPDSegmentBaseNode *segmentBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate timescale=\"123456\""
" duration=\"1\""
" presentationTimeOffset=\"123456789\""
" indexRange=\"100-200\""
" indexRangeExact=\"true\">"
" </SegmentTemplate></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentTemplate = periodNode->SegmentTemplate;
segmentBase = GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentBase;
assert_equals_uint64 (segmentBase->timescale, 123456);
assert_equals_uint64 (segmentBase->presentationTimeOffset, 123456789);
assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 100);
assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 200);
assert_equals_int (segmentBase->indexRangeExact, TRUE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentTemplate MultipleSegmentBaseType SegmentTimeline
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentTemplateNode *segmentTemplate;
GstMPDSegmentTimelineNode *segmentTimeline;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate>"
" <SegmentTimeline>"
" </SegmentTimeline></SegmentTemplate></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentTemplate = periodNode->SegmentTemplate;
segmentTimeline = (GstMPDSegmentTimelineNode *)
GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentTimeline;
fail_if (segmentTimeline == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentTemplate MultipleSegmentBaseType SegmentTimeline
* S attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline_s)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentTemplateNode *segmentTemplate;
GstMPDSegmentTimelineNode *segmentTimeline;
GstMPDSNode *sNode;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate>"
" <SegmentTimeline>"
" <S t=\"1\" d=\"2\" r=\"3\">"
" </S></SegmentTimeline></SegmentTemplate></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentTemplate = periodNode->SegmentTemplate;
segmentTimeline = (GstMPDSegmentTimelineNode *)
GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentTimeline;
sNode = (GstMPDSNode *) g_queue_peek_head (&segmentTimeline->S);
assert_equals_uint64 (sNode->t, 1);
assert_equals_uint64 (sNode->d, 2);
assert_equals_uint64 (sNode->r, 3);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period SegmentTemplate MultipleSegmentBaseType
* BitstreamSwitching attributes
*/
GST_START_TEST
(dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_bitstreamSwitching)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentTemplateNode *segmentTemplate;
GstMPDURLTypeNode *bitstreamSwitching;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate duration=\"1\">"
" <BitstreamSwitching sourceURL=\"TestSourceURL\""
" range=\"100-200\">"
" </BitstreamSwitching></SegmentTemplate></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentTemplate = periodNode->SegmentTemplate;
bitstreamSwitching =
GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->BitstreamSwitching;
assert_equals_string (bitstreamSwitching->sourceURL, "TestSourceURL");
assert_equals_uint64 (bitstreamSwitching->range->first_byte_pos, 100);
assert_equals_uint64 (bitstreamSwitching->range->last_byte_pos, 200);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet id=\"7\""
" group=\"8\""
" lang=\"en\""
" contentType=\"TestContentType\""
" par=\"4:3\""
" minBandwidth=\"100\""
" maxBandwidth=\"200\""
" minWidth=\"1000\""
" maxWidth=\"2000\""
" minHeight=\"1100\""
" maxHeight=\"2100\""
" minFrameRate=\"25/123\""
" maxFrameRate=\"26\""
" segmentAlignment=\"2\""
" subsegmentAlignment=\"false\""
" subsegmentStartsWithSAP=\"6\""
" bitstreamSwitching=\"false\">"
" </AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
assert_equals_uint64 (adaptationSet->id, 7);
assert_equals_uint64 (adaptationSet->group, 8);
assert_equals_string (adaptationSet->lang, "en");
assert_equals_string (adaptationSet->contentType, "TestContentType");
assert_equals_uint64 (adaptationSet->par->num, 4);
assert_equals_uint64 (adaptationSet->par->den, 3);
assert_equals_uint64 (adaptationSet->minBandwidth, 100);
assert_equals_uint64 (adaptationSet->maxBandwidth, 200);
assert_equals_uint64 (adaptationSet->minWidth, 1000);
assert_equals_uint64 (adaptationSet->maxWidth, 2000);
assert_equals_uint64 (adaptationSet->minHeight, 1100);
assert_equals_uint64 (adaptationSet->maxHeight, 2100);
assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
(adaptationSet)->minFrameRate->num, 25);
assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
(adaptationSet)->minFrameRate->den, 123);
assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
(adaptationSet)->maxFrameRate->num, 26);
assert_equals_uint64 (GST_MPD_REPRESENTATION_BASE_NODE
(adaptationSet)->maxFrameRate->den, 1);
assert_equals_int (adaptationSet->segmentAlignment->flag, 1);
assert_equals_uint64 (adaptationSet->segmentAlignment->value, 2);
assert_equals_int (adaptationSet->subsegmentAlignment->flag, 0);
assert_equals_uint64 (adaptationSet->subsegmentAlignment->value, 0);
assert_equals_int (adaptationSet->subsegmentStartsWithSAP, 6);
assert_equals_int (adaptationSet->bitstreamSwitching, 0);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet RepresentationBase attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_representationBase)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet profiles=\"TestProfiles\""
" width=\"100\""
" height=\"200\""
" sar=\"10:20\""
" frameRate=\"30/40\""
" audioSamplingRate=\"TestAudioSamplingRate\""
" mimeType=\"TestMimeType\""
" segmentProfiles=\"TestSegmentProfiles\""
" codecs=\"TestCodecs\""
" maximumSAPPeriod=\"3.4\""
" startWithSAP=\"0\""
" maxPlayoutRate=\"1.2\""
" codingDependency=\"false\""
" scanType=\"progressive\">"
" </AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
assert_equals_string (representationBase->profiles, "TestProfiles");
assert_equals_uint64 (representationBase->width, 100);
assert_equals_uint64 (representationBase->height, 200);
assert_equals_uint64 (representationBase->sar->num, 10);
assert_equals_uint64 (representationBase->sar->den, 20);
assert_equals_uint64 (representationBase->frameRate->num, 30);
assert_equals_uint64 (representationBase->frameRate->den, 40);
assert_equals_string (representationBase->audioSamplingRate,
"TestAudioSamplingRate");
assert_equals_string (representationBase->mimeType, "TestMimeType");
assert_equals_string (representationBase->segmentProfiles,
"TestSegmentProfiles");
assert_equals_string (representationBase->codecs, "TestCodecs");
assert_equals_float (representationBase->maximumSAPPeriod, 3.4);
assert_equals_int (representationBase->startWithSAP, GST_SAP_TYPE_0);
assert_equals_float (representationBase->maxPlayoutRate, 1.2);
assert_equals_float (representationBase->codingDependency, 0);
assert_equals_string (representationBase->scanType, "progressive");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet RepresentationBase FramePacking attributes
*
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representationBase_framePacking) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
GstMPDDescriptorTypeNode *framePacking;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <FramePacking schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </FramePacking></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
framePacking =
(GstMPDDescriptorTypeNode *) representationBase->FramePacking->data;
assert_equals_string (framePacking->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (framePacking->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet RepresentationBase
* AudioChannelConfiguration attributes
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representationBase_audioChannelConfiguration)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
GstMPDDescriptorTypeNode *audioChannelConfiguration;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <AudioChannelConfiguration schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </AudioChannelConfiguration></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
audioChannelConfiguration = (GstMPDDescriptorTypeNode *)
representationBase->AudioChannelConfiguration->data;
assert_equals_string (audioChannelConfiguration->schemeIdUri,
"TestSchemeIdUri");
assert_equals_string (audioChannelConfiguration->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet RepresentationBase ContentProtection
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representationBase_contentProtection) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
GstMPDDescriptorTypeNode *contentProtection;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentProtection schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </ContentProtection></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
gchar *str;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
contentProtection =
(GstMPDDescriptorTypeNode *) representationBase->ContentProtection->data;
assert_equals_string (contentProtection->schemeIdUri, "TestSchemeIdUri");
/* We can't do a simple compare of value (which should be an XML dump
of the ContentProtection element), because the whitespace
formatting from xmlDump might differ between versions of libxml */
str = strstr (contentProtection->value, "<ContentProtection");
fail_if (str == NULL);
str = strstr (contentProtection->value, "value=\"TestValue\"");
fail_if (str == NULL);
str = strstr (contentProtection->value, "</ContentProtection>");
fail_if (str == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet RepresentationBase ContentProtection
* with custom ContentProtection content.
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representationBase_contentProtection_with_content)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
GstMPDDescriptorTypeNode *contentProtection;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" xmlns:customns=\"foo\""
" <Period>"
" <AdaptationSet>"
" <ContentProtection schemeIdUri=\"TestSchemeIdUri\">"
" <customns:bar>Hello world</customns:bar>"
" </ContentProtection></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
gchar *str;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
contentProtection =
(GstMPDDescriptorTypeNode *) representationBase->ContentProtection->data;
assert_equals_string (contentProtection->schemeIdUri, "TestSchemeIdUri");
/* We can't do a simple compare of value (which should be an XML dump
of the ContentProtection element), because the whitespace
formatting from xmlDump might differ between versions of libxml */
str = strstr (contentProtection->value, "<ContentProtection");
fail_if (str == NULL);
str =
strstr (contentProtection->value,
"<customns:bar>Hello world</customns:bar>");
fail_if (str == NULL);
str = strstr (contentProtection->value, "</ContentProtection>");
fail_if (str == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing ContentProtection element that has no value attribute
*/
GST_START_TEST (dash_mpdparser_contentProtection_no_value)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
GstMPDDescriptorTypeNode *contentProtection;
const gchar *xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" xmlns:mspr=\"urn:microsoft:playready\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\" value=\"cenc\"/>"
" <ContentProtection xmlns:mas=\"urn:marlin:mas:1-0:services:schemas:mpd\" schemeIdUri=\"urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4\">"
" <mas:MarlinContentIds>"
" <mas:MarlinContentId>urn:marlin:kid:02020202020202020202020202020202</mas:MarlinContentId>"
" </mas:MarlinContentIds>"
" </ContentProtection>"
" <ContentProtection schemeIdUri=\"urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95\" value=\"MSPR 2.0\">"
" <mspr:pro>dGVzdA==</mspr:pro>"
" </ContentProtection>" "</AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
gchar *str;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
assert_equals_int (g_list_length (representationBase->ContentProtection), 3);
contentProtection = (GstMPDDescriptorTypeNode *)
g_list_nth (representationBase->ContentProtection, 1)->data;
assert_equals_string (contentProtection->schemeIdUri,
"urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4");
fail_if (contentProtection->value == NULL);
/* We can't do a simple compare of value (which should be an XML dump
of the ContentProtection element), because the whitespace
formatting from xmlDump might differ between versions of libxml */
str = strstr (contentProtection->value, "<ContentProtection");
fail_if (str == NULL);
str = strstr (contentProtection->value, "<mas:MarlinContentIds>");
fail_if (str == NULL);
str = strstr (contentProtection->value, "<mas:MarlinContentId>");
fail_if (str == NULL);
str =
strstr (contentProtection->value,
"urn:marlin:kid:02020202020202020202020202020202");
fail_if (str == NULL);
str = strstr (contentProtection->value, "</ContentProtection>");
fail_if (str == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing ContentProtection element that has no value attribute
* nor an XML encoding
*/
GST_START_TEST (dash_mpdparser_contentProtection_no_value_no_encoding)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
GstMPDDescriptorTypeNode *contentProtection;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\" value=\"cenc\"/>"
" <ContentProtection xmlns:mas=\"urn:marlin:mas:1-0:services:schemas:mpd\" schemeIdUri=\"urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4\">"
" <mas:MarlinContentIds>"
" <mas:MarlinContentId>urn:marlin:kid:02020202020202020202020202020202</mas:MarlinContentId>"
" </mas:MarlinContentIds>"
" </ContentProtection>" "</AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
assert_equals_int (g_list_length (representationBase->ContentProtection), 2);
contentProtection = (GstMPDDescriptorTypeNode *)
g_list_nth (representationBase->ContentProtection, 1)->data;
assert_equals_string (contentProtection->schemeIdUri,
"urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4");
fail_if (contentProtection->value == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet RepresentationBase ContentProtection
* attributes
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representationBase_contentProtection_xml_namespaces)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" minBufferTime=\"PT1.500S\""
" type=\"static\" mediaPresentationDuration=\"PT0H24M28.000S\""
" maxSegmentDuration=\"PT0H0M4.000S\""
" profiles=\"urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash264\""
" xmlns:cenc=\"urn:mpeg:cenc:2013\" xmlns:clearkey=\"http://dashif.org/guidelines/clearKey\">"
" <Period>" " <AdaptationSet>"
" <ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\""
" value=\"cenc\" cenc:default_KID=\"33969335-53A5-4E78-BA99-9054CD1B2871\">"
" </ContentProtection>"
" <ContentProtection value=\"ClearKey1.0\""
" schemeIdUri=\"urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e\">"
" <clearkey:Laurl Lic_type=\"EME-1.0\">https://drm.test.example/AcquireLicense</clearkey:Laurl>"
" </ContentProtection></AdaptationSet></Period></MPD>";
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationBaseNode *representationBase;
GstMPDDescriptorTypeNode *contentProtection;
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
xmlDocPtr doc;
xmlNode *root_element = NULL, *node;
xmlChar *property = NULL;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representationBase = GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet);
assert_equals_int (g_list_length (representationBase->ContentProtection), 2);
contentProtection = (GstMPDDescriptorTypeNode *)
g_list_nth_data (representationBase->ContentProtection, 0);
assert_equals_string (contentProtection->schemeIdUri,
"urn:mpeg:dash:mp4protection:2011");
contentProtection = (GstMPDDescriptorTypeNode *)
g_list_nth_data (representationBase->ContentProtection, 1);
assert_equals_string (contentProtection->schemeIdUri,
"urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e");
/* We can't do a simple string compare of value, because the whitespace
formatting from xmlDump might differ between versions of libxml */
LIBXML_TEST_VERSION;
doc =
xmlReadMemory (contentProtection->value,
strlen (contentProtection->value), "ContentProtection.xml", NULL,
XML_PARSE_NONET);
fail_if (!doc);
root_element = xmlDocGetRootElement (doc);
fail_if (root_element->type != XML_ELEMENT_NODE);
fail_if (xmlStrcmp (root_element->name,
(xmlChar *) "ContentProtection") != 0);
fail_if ((property =
xmlGetNoNsProp (root_element, (const xmlChar *) "value")) == NULL);
fail_if (xmlStrcmp (property, (xmlChar *) "ClearKey1.0") != 0);
xmlFree (property);
fail_if ((property =
xmlGetNoNsProp (root_element,
(const xmlChar *) "schemeIdUri")) == NULL);
assert_equals_string ((const gchar *) property,
"urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e");
xmlFree (property);
for (node = root_element->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE)
break;
}
assert_equals_string ((const gchar *) node->name, "Laurl");
assert_equals_string ((const gchar *) node->children->content,
"https://drm.test.example/AcquireLicense");
xmlFreeDoc (doc);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Accessibility attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_accessibility)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDDescriptorTypeNode *accessibility;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Accessibility schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Accessibility></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
accessibility =
(GstMPDDescriptorTypeNode *) adaptationSet->Accessibility->data;
assert_equals_string (accessibility->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (accessibility->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Role attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_role)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDDescriptorTypeNode *role;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Role schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Role></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
role = (GstMPDDescriptorTypeNode *) adaptationSet->Role->data;
assert_equals_string (role->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (role->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Rating attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_rating)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDDescriptorTypeNode *rating;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Rating schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Rating></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
rating = (GstMPDDescriptorTypeNode *) adaptationSet->Rating->data;
assert_equals_string (rating->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (rating->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Viewpoint attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_viewpoint)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDDescriptorTypeNode *viewpoint;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Viewpoint schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Viewpoint></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
viewpoint = (GstMPDDescriptorTypeNode *) adaptationSet->Viewpoint->data;
assert_equals_string (viewpoint->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (viewpoint->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet ContentComponent attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDContentComponentNode *contentComponent;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentComponent id=\"1\""
" lang=\"en\""
" contentType=\"TestContentType\""
" par=\"10:20\">"
" </ContentComponent></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
contentComponent = (GstMPDContentComponentNode *)
adaptationSet->ContentComponents->data;
assert_equals_uint64 (contentComponent->id, 1);
assert_equals_string (contentComponent->lang, "en");
assert_equals_string (contentComponent->contentType, "TestContentType");
assert_equals_uint64 (contentComponent->par->num, 10);
assert_equals_uint64 (contentComponent->par->den, 20);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet ContentComponent Accessibility attributes
*
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_contentComponent_accessibility) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDContentComponentNode *contentComponent;
GstMPDDescriptorTypeNode *accessibility;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentComponent>"
" <Accessibility schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Accessibility>"
" </ContentComponent></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
contentComponent = (GstMPDContentComponentNode *)
adaptationSet->ContentComponents->data;
accessibility =
(GstMPDDescriptorTypeNode *) contentComponent->Accessibility->data;
assert_equals_string (accessibility->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (accessibility->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet ContentComponent Role attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent_role)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDContentComponentNode *contentComponent;
GstMPDDescriptorTypeNode *role;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentComponent>"
" <Role schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Role></ContentComponent></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
contentComponent = (GstMPDContentComponentNode *)
adaptationSet->ContentComponents->data;
role = (GstMPDDescriptorTypeNode *) contentComponent->Role->data;
assert_equals_string (role->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (role->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet ContentComponent Rating attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent_rating)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDContentComponentNode *contentComponent;
GstMPDDescriptorTypeNode *rating;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentComponent>"
" <Rating schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Rating>"
" </ContentComponent></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
contentComponent = (GstMPDContentComponentNode *)
adaptationSet->ContentComponents->data;
rating = (GstMPDDescriptorTypeNode *) contentComponent->Rating->data;
assert_equals_string (rating->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (rating->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet ContentComponent Viewpoint attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_contentComponent_viewpoint)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDContentComponentNode *contentComponent;
GstMPDDescriptorTypeNode *viewpoint;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <ContentComponent>"
" <Viewpoint schemeIdUri=\"TestSchemeIdUri\""
" value=\"TestValue\">"
" </Viewpoint>"
" </ContentComponent></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
contentComponent = (GstMPDContentComponentNode *)
adaptationSet->ContentComponents->data;
viewpoint = (GstMPDDescriptorTypeNode *) contentComponent->Viewpoint->data;
assert_equals_string (viewpoint->schemeIdUri, "TestSchemeIdUri");
assert_equals_string (viewpoint->value, "TestValue");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet BaseURL attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_baseURL)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDBaseURLNode *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <BaseURL serviceLocation=\"TestServiceLocation\""
" byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
" </AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
baseURL = (GstMPDBaseURLNode *) adaptationSet->BaseURLs->data;
assert_equals_string (baseURL->baseURL, "TestBaseURL");
assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
assert_equals_string (baseURL->byteRange, "TestByteRange");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet SegmentBase attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentBase)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDSegmentBaseNode *segmentBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <SegmentBase timescale=\"123456\""
" presentationTimeOffset=\"123456789\""
" indexRange=\"100-200\""
" indexRangeExact=\"true\">"
" </SegmentBase></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
segmentBase = adaptationSet->SegmentBase;
assert_equals_uint64 (segmentBase->timescale, 123456);
assert_equals_uint64 (segmentBase->presentationTimeOffset, 123456789);
assert_equals_uint64 (segmentBase->indexRange->first_byte_pos, 100);
assert_equals_uint64 (segmentBase->indexRange->last_byte_pos, 200);
assert_equals_int (segmentBase->indexRangeExact, TRUE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet SegmentBase Initialization attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentBase_initialization)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDSegmentBaseNode *segmentBase;
GstMPDURLTypeNode *initialization;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <SegmentBase>"
" <Initialisation sourceURL=\"TestSourceURL\""
" range=\"100-200\">"
" </Initialisation></SegmentBase></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
segmentBase = adaptationSet->SegmentBase;
initialization = segmentBase->Initialization;
assert_equals_string (initialization->sourceURL, "TestSourceURL");
assert_equals_uint64 (initialization->range->first_byte_pos, 100);
assert_equals_uint64 (initialization->range->last_byte_pos, 200);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet SegmentBase RepresentationIndex attributes
*
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_segmentBase_representationIndex) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDSegmentBaseNode *segmentBase;
GstMPDURLTypeNode *representationIndex;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <SegmentBase>"
" <RepresentationIndex sourceURL=\"TestSourceURL\""
" range=\"100-200\">"
" </RepresentationIndex>"
" </SegmentBase></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
segmentBase = adaptationSet->SegmentBase;
representationIndex = segmentBase->RepresentationIndex;
assert_equals_string (representationIndex->sourceURL, "TestSourceURL");
assert_equals_uint64 (representationIndex->range->first_byte_pos, 100);
assert_equals_uint64 (representationIndex->range->last_byte_pos, 200);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet SegmentList attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentList)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDSegmentListNode *segmentList;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <SegmentList duration=\"1\"></SegmentList></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
segmentList = adaptationSet->SegmentList;
fail_if (segmentList == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet SegmentTemplate attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentTemplate)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDSegmentTemplateNode *segmentTemplate;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <SegmentTemplate media=\"TestMedia\""
" duration=\"1\""
" index=\"TestIndex\""
" initialization=\"TestInitialization\""
" bitstreamSwitching=\"TestBitstreamSwitching\">"
" </SegmentTemplate></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
segmentTemplate = adaptationSet->SegmentTemplate;
assert_equals_string (segmentTemplate->media, "TestMedia");
assert_equals_string (segmentTemplate->index, "TestIndex");
assert_equals_string (segmentTemplate->initialization, "TestInitialization");
assert_equals_string (segmentTemplate->bitstreamSwitching,
"TestBitstreamSwitching");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representation_segmentTemplate_inherit)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSegmentTemplateNode *segmentTemplate;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate media=\"ParentMedia\" duration=\"1\" "
" initialization=\"ParentInitialization\">"
" </SegmentTemplate>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"5000\">"
" <SegmentTemplate media=\"TestMedia\""
" index=\"TestIndex\""
" bitstreamSwitching=\"TestBitstreamSwitching\">"
" </SegmentTemplate></Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation =
(GstMPDRepresentationNode *) adaptationSet->Representations->data;
segmentTemplate = representation->SegmentTemplate;
assert_equals_string (segmentTemplate->media, "TestMedia");
assert_equals_string (segmentTemplate->index, "TestIndex");
assert_equals_string (segmentTemplate->initialization,
"ParentInitialization");
assert_equals_string (segmentTemplate->bitstreamSwitching,
"TestBitstreamSwitching");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representation_segmentBase_inherit) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSegmentBaseNode *segmentBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentBase timescale=\"123456\""
" presentationTimeOffset=\"123456789\""
" indexRange=\"100-200\""
" indexRangeExact=\"true\">"
" <Initialisation sourceURL=\"TestSourceURL\""
" range=\"100-200\" />"
" </SegmentBase>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"5000\">"
" <SegmentBase>"
" </SegmentBase></Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation =
(GstMPDRepresentationNode *) adaptationSet->Representations->data;
segmentBase = representation->SegmentBase;
assert_equals_int (segmentBase->timescale, 123456);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet SegmentTemplate attributes with
* inheritance
*/
GST_START_TEST (dash_mpdparser_adapt_repr_segmentTemplate_inherit)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDSegmentTemplateNode *segmentTemplate;
GstMPDRepresentationNode *representation;
GstMPDSegmentBaseNode *segmentBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period duration=\"PT0H5M0.000S\">"
" <AdaptationSet maxWidth=\"1280\" maxHeight=\"720\" maxFrameRate=\"50\">"
" <SegmentTemplate initialization=\"set1_init.mp4\"/>"
" <Representation id=\"1\" mimeType=\"video/mp4\" codecs=\"avc1.640020\" "
" width=\"1280\" height=\"720\" frameRate=\"50\" bandwidth=\"30000\">"
" <SegmentTemplate timescale=\"12800\" media=\"track1_$Number$.m4s\" startNumber=\"1\" duration=\"25600\"/>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
segmentTemplate = representation->SegmentTemplate;
fail_if (segmentTemplate == NULL);
segmentBase = GST_MPD_MULT_SEGMENT_BASE_NODE (segmentTemplate)->SegmentBase;
assert_equals_uint64 (segmentBase->timescale, 12800);
assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
(segmentTemplate)->duration, 25600);
assert_equals_uint64 (GST_MPD_MULT_SEGMENT_BASE_NODE
(segmentTemplate)->startNumber, 1);
assert_equals_string (segmentTemplate->media, "track1_$Number$.m4s");
assert_equals_string (segmentTemplate->initialization, "set1_init.mp4");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet SegmentTemplate attributes with
* inheritance
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_segmentTemplate_inherit)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDSegmentTemplateNode *segmentTemplate;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <SegmentTemplate media=\"ParentMedia\" duration=\"1\" "
" initialization=\"ParentInitialization\">"
" </SegmentTemplate>"
" <AdaptationSet>"
" <SegmentTemplate media=\"TestMedia\""
" duration=\"1\""
" index=\"TestIndex\""
" bitstreamSwitching=\"TestBitstreamSwitching\">"
" </SegmentTemplate></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
segmentTemplate = adaptationSet->SegmentTemplate;
assert_equals_string (segmentTemplate->media, "TestMedia");
assert_equals_string (segmentTemplate->index, "TestIndex");
assert_equals_string (segmentTemplate->initialization,
"ParentInitialization");
assert_equals_string (segmentTemplate->bitstreamSwitching,
"TestBitstreamSwitching");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_representation)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"Test_Id\""
" bandwidth=\"100\""
" qualityRanking=\"200\""
" dependencyId=\"one two three\""
" mediaStreamStructureId=\"\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
assert_equals_string (representation->id, "Test_Id");
assert_equals_uint64 (representation->bandwidth, 100);
assert_equals_uint64 (representation->qualityRanking, 200);
assert_equals_string (representation->dependencyId[0], "one");
assert_equals_string (representation->dependencyId[1], "two");
assert_equals_string (representation->dependencyId[2], "three");
assert_equals_pointer (representation->dependencyId[3], NULL);
assert_equals_pointer (representation->mediaStreamStructureId[0], NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation RepresentationBaseType attributes
*
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representation_representationBase) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
fail_if (representation == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation BaseURL attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_representation_baseURL)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDBaseURLNode *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <BaseURL serviceLocation=\"TestServiceLocation\""
" byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
baseURL = (GstMPDBaseURLNode *) representation->BaseURLs->data;
assert_equals_string (baseURL->baseURL, "TestBaseURL");
assert_equals_string (baseURL->serviceLocation, "TestServiceLocation");
assert_equals_string (baseURL->byteRange, "TestByteRange");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation SubRepresentation attributes
*
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representation_subRepresentation) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSubRepresentationNode *subRepresentation;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SubRepresentation level=\"100\""
" dependencyLevel=\"1 2 3\""
" bandwidth=\"200\""
" contentComponent=\"content1 content2\">"
" </SubRepresentation>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
subRepresentation = (GstMPDSubRepresentationNode *)
representation->SubRepresentations->data;
assert_equals_uint64 (subRepresentation->level, 100);
assert_equals_uint64 (subRepresentation->dependencyLevel_size, 3);
assert_equals_uint64 (subRepresentation->dependencyLevel[0], 1);
assert_equals_uint64 (subRepresentation->dependencyLevel[1], 2);
assert_equals_uint64 (subRepresentation->dependencyLevel[2], 3);
assert_equals_uint64 (subRepresentation->bandwidth, 200);
assert_equals_string (subRepresentation->contentComponent[0], "content1");
assert_equals_string (subRepresentation->contentComponent[1], "content2");
assert_equals_pointer (subRepresentation->contentComponent[2], NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation SubRepresentation
* RepresentationBase attributes
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representation_subRepresentation_representationBase)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSubRepresentationNode *subRepresentation;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SubRepresentation>"
" </SubRepresentation>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
subRepresentation = (GstMPDSubRepresentationNode *)
representation->SubRepresentations->data;
fail_if (subRepresentation == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation SegmentBase attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_representation_segmentBase)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSegmentBaseNode *segmentBase;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentBase>"
" </SegmentBase>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
segmentBase = representation->SegmentBase;
fail_if (segmentBase == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation SegmentList attributes
*
*/
GST_START_TEST (dash_mpdparser_period_adaptationSet_representation_segmentList)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSegmentListNode *segmentList;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList duration=\"1\">"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
segmentList = representation->SegmentList;
fail_if (segmentList == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period AdaptationSet Representation SegmentTemplate attributes
*
*/
GST_START_TEST
(dash_mpdparser_period_adaptationSet_representation_segmentTemplate) {
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSegmentTemplateNode *segmentTemplate;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentTemplate duration=\"1\">"
" </SegmentTemplate>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
segmentTemplate = representation->SegmentTemplate;
fail_if (segmentTemplate == NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing Period Subset attributes
*
*/
GST_START_TEST (dash_mpdparser_period_subset)
{
GstMPDPeriodNode *periodNode;
GstMPDSubsetNode *subset;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period><Subset contains=\"1 2 3\"></Subset></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
subset = (GstMPDSubsetNode *) periodNode->Subsets->data;
assert_equals_uint64 (subset->contains_size, 3);
assert_equals_uint64 (subset->contains[0], 1);
assert_equals_uint64 (subset->contains[1], 2);
assert_equals_uint64 (subset->contains[2], 3);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
dashdemux: add support for UTCTiming elements for clock drift compensation Unless the DASH client can compensate for the difference between its clock and the clock used by the server, the client might request fragments that either not yet on the server or fragments that have already been expired from the server. This is an issue because these requests can propagate all the way back to the origin ISO/IEC 23009-1:2014/Amd 1 [PDAM1] defines a new UTCTiming element to allow a DASH client to track the clock used by the server generating the DASH stream. Multiple UTCTiming elements might be present, to indicate support for multiple methods of UTC time gathering. Each element can contain a white space separated list of URLs that can be contacted to discover the UTC time from the server's perspective. This commit provides parsing of UTCTiming elements, unit tests of this parsing and a function to poll a time server. This function supports the following methods: urn:mpeg:dash:utc:ntp:2014 urn:mpeg:dash:utc:http-xsdate:2014 urn:mpeg:dash:utc:http-iso:2014 urn:mpeg:dash:utc:http-ntp:2014 The manifest update task is used to poll the clock time server, to save having to create a new thread. When choosing the starting fragment number and when waiting for a fragment to become available, the difference between the server's idea of UTC and the client's idea of UTC is taken into account. For example, if the server's time is behind the client's idea of UTC, we wait for longer before requesting a fragment [PDAM1]: http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=66068 dashdemux: support NTP time servers in UTCTiming elements Use the gst_ntp_clock to support the use of an NTP server. https://bugzilla.gnome.org/show_bug.cgi?id=752413
2015-07-15 10:56:13 +00:00
/*
* Test parsing UTCTiming elements
*
*/
GST_START_TEST (dash_mpdparser_utctiming)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
"<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-xsdate:2014\" value=\"http://time.akamai.com/?iso http://example.time/xsdate\"/>"
"<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:direct:2014\" value=\"2002-05-30T09:30:10Z \"/>"
"<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:ntp:2014\" value=\"0.europe.pool.ntp.org 1.europe.pool.ntp.org 2.europe.pool.ntp.org 3.europe.pool.ntp.org\"/>"
"</MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
dashdemux: add support for UTCTiming elements for clock drift compensation Unless the DASH client can compensate for the difference between its clock and the clock used by the server, the client might request fragments that either not yet on the server or fragments that have already been expired from the server. This is an issue because these requests can propagate all the way back to the origin ISO/IEC 23009-1:2014/Amd 1 [PDAM1] defines a new UTCTiming element to allow a DASH client to track the clock used by the server generating the DASH stream. Multiple UTCTiming elements might be present, to indicate support for multiple methods of UTC time gathering. Each element can contain a white space separated list of URLs that can be contacted to discover the UTC time from the server's perspective. This commit provides parsing of UTCTiming elements, unit tests of this parsing and a function to poll a time server. This function supports the following methods: urn:mpeg:dash:utc:ntp:2014 urn:mpeg:dash:utc:http-xsdate:2014 urn:mpeg:dash:utc:http-iso:2014 urn:mpeg:dash:utc:http-ntp:2014 The manifest update task is used to poll the clock time server, to save having to create a new thread. When choosing the starting fragment number and when waiting for a fragment to become available, the difference between the server's idea of UTC and the client's idea of UTC is taken into account. For example, if the server's time is behind the client's idea of UTC, we wait for longer before requesting a fragment [PDAM1]: http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=66068 dashdemux: support NTP time servers in UTCTiming elements Use the gst_ntp_clock to support the use of an NTP server. https://bugzilla.gnome.org/show_bug.cgi?id=752413
2015-07-15 10:56:13 +00:00
GstMPDUTCTimingType selected_method;
gchar **urls;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
dashdemux: add support for UTCTiming elements for clock drift compensation Unless the DASH client can compensate for the difference between its clock and the clock used by the server, the client might request fragments that either not yet on the server or fragments that have already been expired from the server. This is an issue because these requests can propagate all the way back to the origin ISO/IEC 23009-1:2014/Amd 1 [PDAM1] defines a new UTCTiming element to allow a DASH client to track the clock used by the server generating the DASH stream. Multiple UTCTiming elements might be present, to indicate support for multiple methods of UTC time gathering. Each element can contain a white space separated list of URLs that can be contacted to discover the UTC time from the server's perspective. This commit provides parsing of UTCTiming elements, unit tests of this parsing and a function to poll a time server. This function supports the following methods: urn:mpeg:dash:utc:ntp:2014 urn:mpeg:dash:utc:http-xsdate:2014 urn:mpeg:dash:utc:http-iso:2014 urn:mpeg:dash:utc:http-ntp:2014 The manifest update task is used to poll the clock time server, to save having to create a new thread. When choosing the starting fragment number and when waiting for a fragment to become available, the difference between the server's idea of UTC and the client's idea of UTC is taken into account. For example, if the server's time is behind the client's idea of UTC, we wait for longer before requesting a fragment [PDAM1]: http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=66068 dashdemux: support NTP time servers in UTCTiming elements Use the gst_ntp_clock to support the use of an NTP server. https://bugzilla.gnome.org/show_bug.cgi?id=752413
2015-07-15 10:56:13 +00:00
assert_equals_int (ret, TRUE);
fail_if (mpdclient->mpd_root_node == NULL);
fail_if (mpdclient->mpd_root_node->UTCTimings == NULL);
assert_equals_int (g_list_length (mpdclient->mpd_root_node->UTCTimings), 3);
dashdemux: add support for UTCTiming elements for clock drift compensation Unless the DASH client can compensate for the difference between its clock and the clock used by the server, the client might request fragments that either not yet on the server or fragments that have already been expired from the server. This is an issue because these requests can propagate all the way back to the origin ISO/IEC 23009-1:2014/Amd 1 [PDAM1] defines a new UTCTiming element to allow a DASH client to track the clock used by the server generating the DASH stream. Multiple UTCTiming elements might be present, to indicate support for multiple methods of UTC time gathering. Each element can contain a white space separated list of URLs that can be contacted to discover the UTC time from the server's perspective. This commit provides parsing of UTCTiming elements, unit tests of this parsing and a function to poll a time server. This function supports the following methods: urn:mpeg:dash:utc:ntp:2014 urn:mpeg:dash:utc:http-xsdate:2014 urn:mpeg:dash:utc:http-iso:2014 urn:mpeg:dash:utc:http-ntp:2014 The manifest update task is used to poll the clock time server, to save having to create a new thread. When choosing the starting fragment number and when waiting for a fragment to become available, the difference between the server's idea of UTC and the client's idea of UTC is taken into account. For example, if the server's time is behind the client's idea of UTC, we wait for longer before requesting a fragment [PDAM1]: http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=66068 dashdemux: support NTP time servers in UTCTiming elements Use the gst_ntp_clock to support the use of an NTP server. https://bugzilla.gnome.org/show_bug.cgi?id=752413
2015-07-15 10:56:13 +00:00
urls =
gst_mpd_client_get_utc_timing_sources (mpdclient,
GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE, &selected_method);
fail_if (urls == NULL);
assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE);
assert_equals_int (g_strv_length (urls), 2);
assert_equals_string (urls[0], "http://time.akamai.com/?iso");
assert_equals_string (urls[1], "http://example.time/xsdate");
urls =
gst_mpd_client_get_utc_timing_sources (mpdclient,
GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE | GST_MPD_UTCTIMING_TYPE_HTTP_ISO,
&selected_method);
fail_if (urls == NULL);
assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE);
urls =
gst_mpd_client_get_utc_timing_sources (mpdclient,
GST_MPD_UTCTIMING_TYPE_DIRECT, NULL);
fail_if (urls == NULL);
assert_equals_int (g_strv_length (urls), 1);
assert_equals_string (urls[0], "2002-05-30T09:30:10Z ");
urls =
gst_mpd_client_get_utc_timing_sources (mpdclient,
GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE | GST_MPD_UTCTIMING_TYPE_DIRECT,
&selected_method);
fail_if (urls == NULL);
assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE);
urls =
gst_mpd_client_get_utc_timing_sources (mpdclient,
GST_MPD_UTCTIMING_TYPE_NTP, &selected_method);
fail_if (urls == NULL);
assert_equals_int (selected_method, GST_MPD_UTCTIMING_TYPE_NTP);
assert_equals_int (g_strv_length (urls), 4);
assert_equals_string (urls[0], "0.europe.pool.ntp.org");
assert_equals_string (urls[1], "1.europe.pool.ntp.org");
assert_equals_string (urls[2], "2.europe.pool.ntp.org");
assert_equals_string (urls[3], "3.europe.pool.ntp.org");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing invalid UTCTiming values:
* - elements with no schemeIdUri property should be rejected
* - elements with no value property should be rejected
* - elements with unrecognised UTCTiming scheme should be rejected
* - elements with empty values should be rejected
*
*/
GST_START_TEST (dash_mpdparser_utctiming_invalid_value)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
"<UTCTiming invalid_schemeIdUri=\"dummy.uri.scheme\" value=\"dummy value\"/>"
"<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:ntp:2014\" invalid_value=\"dummy value\"/>"
"<UTCTiming schemeIdUri=\"dummy.uri.scheme\" value=\"dummy value\"/>"
"<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:ntp:2014\" value=\"\"/>"
"</MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
fail_if (mpdclient->mpd_root_node == NULL);
fail_if (mpdclient->mpd_root_node->UTCTimings != NULL);
dashdemux: add support for UTCTiming elements for clock drift compensation Unless the DASH client can compensate for the difference between its clock and the clock used by the server, the client might request fragments that either not yet on the server or fragments that have already been expired from the server. This is an issue because these requests can propagate all the way back to the origin ISO/IEC 23009-1:2014/Amd 1 [PDAM1] defines a new UTCTiming element to allow a DASH client to track the clock used by the server generating the DASH stream. Multiple UTCTiming elements might be present, to indicate support for multiple methods of UTC time gathering. Each element can contain a white space separated list of URLs that can be contacted to discover the UTC time from the server's perspective. This commit provides parsing of UTCTiming elements, unit tests of this parsing and a function to poll a time server. This function supports the following methods: urn:mpeg:dash:utc:ntp:2014 urn:mpeg:dash:utc:http-xsdate:2014 urn:mpeg:dash:utc:http-iso:2014 urn:mpeg:dash:utc:http-ntp:2014 The manifest update task is used to poll the clock time server, to save having to create a new thread. When choosing the starting fragment number and when waiting for a fragment to become available, the difference between the server's idea of UTC and the client's idea of UTC is taken into account. For example, if the server's time is behind the client's idea of UTC, we wait for longer before requesting a fragment [PDAM1]: http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=66068 dashdemux: support NTP time servers in UTCTiming elements Use the gst_ntp_clock to support the use of an NTP server. https://bugzilla.gnome.org/show_bug.cgi?id=752413
2015-07-15 10:56:13 +00:00
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing the type property: value "dynamic"
*
*/
GST_START_TEST (dash_mpdparser_type_dynamic)
{
gboolean isLive;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD type=\"dynamic\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"> </MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
isLive = gst_mpd_client_is_live (mpdclient);
assert_equals_int (isLive, 1);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Validate gst_mpdparser_build_URL_from_template function
*
*/
GST_START_TEST (dash_mpdparser_template_parsing)
{
const gchar *id = "TestId";
guint number = 7;
guint bandwidth = 2500;
guint64 time = 100;
gchar *result;
struct TestUrl
{
const gchar *urlTemplate;
const gchar *expectedResponse;
};
/* various test scenarios to attempt */
struct TestUrl testUrl[] = {
{"", NULL}, /* empty string for template */
{"$$", "$"}, /* escaped $ */
{"Number", "Number"}, /* string similar with an identifier, but without $ */
{"Number$Number$", "Number7"}, /* Number identifier */
{"Number$Number$$$", "Number7$"}, /* Number identifier followed by $$ */
{"Number$Number$Number$Number$", "Number7Number7"}, /* series of "Number" string and Number identifier */
{"Representation$RepresentationID$", "RepresentationTestId"}, /* RepresentationID identifier */
{"TestMedia$Bandwidth$$$test", "TestMedia2500$test"}, /* Bandwidth identifier */
{"TestMedia$Time$", "TestMedia100"}, /* Time identifier */
{"TestMedia$Time", NULL}, /* Identifier not finished with $ */
{"Time$Time%d$", NULL}, /* usage of %d (no width) */
{"Time$Time%0d$", "Time100"}, /* usage of format smaller than number of digits */
{"Time$Time%01d$", "Time100"}, /* usage of format smaller than number of digits */
{"Time$Time%05d$", "Time00100"}, /* usage of format bigger than number of digits */
{"Time$Time%05dtest$", "Time00100test"}, /* usage extra text in format */
{"Time$Time%3d$", NULL}, /* incorrect format: width does not start with 0 */
{"Time$Time%0-4d$", NULL}, /* incorrect format: width is not a number */
{"Time$Time%0$", NULL}, /* incorrect format: no d, x or u */
{"Time$Time1%01d$", NULL}, /* incorrect format: does not start with % after identifier */
{"$Bandwidth%/init.mp4v", NULL}, /* incorrect identifier: not finished with $ */
{"$Number%/$Time$.mp4v", NULL}, /* incorrect number of $ separators */
{"$RepresentationID1$", NULL}, /* incorrect identifier */
{"$Bandwidth1$", NULL}, /* incorrect identifier */
{"$Number1$", NULL}, /* incorrect identifier */
{"$RepresentationID%01d$", NULL}, /* incorrect format: RepresentationID does not support formatting */
{"Time$Time%05u$", NULL}, /* %u format */
{"Time$Time%05x$", NULL}, /* %x format */
{"Time$Time%05utest$", NULL}, /* %u format followed by text */
{"Time$Time%05xtest$", NULL}, /* %x format followed by text */
{"Time$Time%05xtest%$", NULL}, /* second % character in format */
};
guint count = sizeof (testUrl) / sizeof (testUrl[0]);
gint i;
for (i = 0; i < count; i++) {
result =
gst_mpdparser_build_URL_from_template (testUrl[i].urlTemplate, id,
number, bandwidth, time);
assert_equals_string (result, testUrl[i].expectedResponse);
g_free (result);
}
}
GST_END_TEST;
/*
* Test handling isoff ondemand profile
*
*/
GST_START_TEST (dash_mpdparser_isoff_ondemand_profile)
{
gboolean hasOnDemandProfile;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\"></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
hasOnDemandProfile = gst_mpd_client_has_isoff_ondemand_profile (mpdclient);
assert_equals_int (hasOnDemandProfile, 1);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling GstDateTime
*
*/
GST_START_TEST (dash_mpdparser_GstDateTime)
{
gint64 delta;
GstDateTime *time1;
GstDateTime *time2;
GstDateTime *time3;
GDateTime *g_time2;
GDateTime *g_time3;
time1 = gst_date_time_new_from_iso8601_string ("2012-06-23T23:30:59Z");
time2 = gst_date_time_new_from_iso8601_string ("2012-06-23T23:31:00Z");
delta = gst_mpd_client_calculate_time_difference (time1, time2);
assert_equals_int64 (delta, 1 * GST_SECOND);
time3 =
gst_mpd_client_add_time_difference (time1, GST_TIME_AS_USECONDS (delta));
/* convert to GDateTime in order to compare time2 and time 3 */
g_time2 = gst_date_time_to_g_date_time (time2);
g_time3 = gst_date_time_to_g_date_time (time3);
fail_if (g_date_time_compare (g_time2, g_time3) != 0);
gst_date_time_unref (time1);
gst_date_time_unref (time2);
gst_date_time_unref (time3);
g_date_time_unref (g_time2);
g_date_time_unref (g_time3);
}
GST_END_TEST;
/*
* Test bitstreamSwitching inheritance from Period to AdaptationSet
*
* Description of bistreamSwitching attribute in Period:
* "When set to true, this is equivalent as if the
* AdaptationSet@bitstreamSwitching for each Adaptation Set contained in this
* Period is set to 'true'. In this case, the AdaptationSet@bitstreamSwitching
* attribute shall not be set to 'false' for any Adaptation Set in this Period"
*
*/
GST_START_TEST (dash_mpdparser_bitstreamSwitching_inheritance)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
guint activeStreams;
GstActiveStream *activeStream;
GstCaps *caps;
GstStructure *s;
gboolean bitstreamSwitchingFlag;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\""
" duration=\"P0Y0M1DT1H1M1S\""
" bitstreamSwitching=\"true\">"
" <AdaptationSet id=\"1\""
" mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation>"
" </AdaptationSet>"
" <AdaptationSet id=\"2\""
" mimeType=\"audio\""
" bitstreamSwitching=\"false\">"
" <Representation id=\"2\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* setup streaming from the second adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 1);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* 2 active streams */
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, 2);
/* get details of the first active stream */
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
assert_equals_int (activeStream->mimeType, GST_STREAM_VIDEO);
caps = gst_mpd_client_get_stream_caps (activeStream);
fail_unless (caps != NULL);
s = gst_caps_get_structure (caps, 0);
assert_equals_string (gst_structure_get_name (s), "video/quicktime");
gst_caps_unref (caps);
/* inherited from Period's bitstreamSwitching */
bitstreamSwitchingFlag =
gst_mpd_client_get_bitstream_switching_flag (activeStream);
assert_equals_int (bitstreamSwitchingFlag, TRUE);
/* get details of the second active stream */
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 1);
fail_if (activeStream == NULL);
assert_equals_int (activeStream->mimeType, GST_STREAM_AUDIO);
caps = gst_mpd_client_get_stream_caps (activeStream);
fail_unless (caps != NULL);
s = gst_caps_get_structure (caps, 0);
assert_equals_string (gst_structure_get_name (s), "audio");
gst_caps_unref (caps);
/* set to FALSE in our example, but overwritten to TRUE by Period's
* bitstreamSwitching
*/
bitstreamSwitchingFlag =
gst_mpd_client_get_bitstream_switching_flag (activeStream);
assert_equals_int (bitstreamSwitchingFlag, TRUE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test various duration formats
*/
GST_START_TEST (dash_mpdparser_various_duration_formats)
{
GstMPDPeriodNode *periodNode;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P100Y\">"
" <Period id=\"Period0\" start=\"PT1S\"></Period>"
" <Period id=\"Period1\" start=\"PT1.5S\"></Period>"
" <Period id=\"Period2\" start=\"PT1,7S\"></Period>"
" <Period id=\"Period3\" start=\"PT1M\"></Period>"
" <Period id=\"Period4\" start=\"PT1H\"></Period>"
" <Period id=\"Period5\" start=\"P1D\"></Period>"
" <Period id=\"Period6\" start=\"P1M\"></Period>"
" <Period id=\"Period7\" start=\"P1Y\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
0);
assert_equals_string (periodNode->id, "Period0");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 0, 0, 0, 0, 1, 0));
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
1);
assert_equals_string (periodNode->id, "Period1");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 0, 0, 0, 0, 1, 500));
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
2);
assert_equals_string (periodNode->id, "Period2");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 0, 0, 0, 0, 1, 700));
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
3);
assert_equals_string (periodNode->id, "Period3");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 0, 0, 0, 1, 0, 0));
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
4);
assert_equals_string (periodNode->id, "Period4");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 0, 0, 1, 0, 0, 0));
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
5);
assert_equals_string (periodNode->id, "Period5");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 0, 1, 0, 0, 0, 0));
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
6);
assert_equals_string (periodNode->id, "Period6");
assert_equals_uint64 (periodNode->start,
duration_to_ms (0, 1, 0, 0, 0, 0, 0));
periodNode =
(GstMPDPeriodNode *) g_list_nth_data (mpdclient->mpd_root_node->Periods,
7);
assert_equals_string (periodNode->id, "Period7");
assert_equals_uint64 (periodNode->start,
duration_to_ms (1, 0, 0, 0, 0, 0, 0));
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test media presentation setup
*
*/
GST_START_TEST (dash_mpdparser_setup_media_presentation)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\""
" duration=\"P0Y0M1DT1H1M1S\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test setting a stream
*
*/
GST_START_TEST (dash_mpdparser_setup_streaming)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\""
" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\""
" mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the first adaptation set of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
adapt_set = (GstMPDAdaptationSetNode *) adaptationSets->data;
fail_if (adapt_set == NULL);
/* setup streaming from the adaptation set */
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling Period selection
*
*/
GST_START_TEST (dash_mpdparser_period_selection)
{
const gchar *periodName;
guint periodIndex;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" mediaPresentationDuration=\"P0Y0M1DT1H4M3S\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\"></Period>"
" <Period id=\"Period1\"></Period>"
" <Period id=\"Period2\" start=\"P0Y0M1DT1H3M3S\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* period_idx should be 0 and we should have no active periods */
assert_equals_uint64 (mpdclient->period_idx, 0);
fail_unless (mpdclient->periods == NULL);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* check the periods */
fail_unless (mpdclient->periods != NULL);
periodName = gst_mpd_client_get_period_id (mpdclient);
assert_equals_string (periodName, "Period0");
ret = gst_mpd_client_set_period_index (mpdclient, 1);
assert_equals_int (ret, TRUE);
periodName = gst_mpd_client_get_period_id (mpdclient);
assert_equals_string (periodName, "Period1");
ret = gst_mpd_client_set_period_index (mpdclient, 2);
assert_equals_int (ret, TRUE);
periodName = gst_mpd_client_get_period_id (mpdclient);
assert_equals_string (periodName, "Period2");
ret = gst_mpd_client_has_next_period (mpdclient);
assert_equals_int (ret, FALSE);
ret = gst_mpd_client_has_previous_period (mpdclient);
assert_equals_int (ret, TRUE);
ret = gst_mpd_client_set_period_index (mpdclient, 0);
assert_equals_int (ret, TRUE);
ret = gst_mpd_client_has_next_period (mpdclient);
assert_equals_int (ret, TRUE);
ret = gst_mpd_client_has_previous_period (mpdclient);
assert_equals_int (ret, FALSE);
ret = gst_mpd_client_set_period_id (mpdclient, "Period1");
assert_equals_int (ret, TRUE);
periodIndex = gst_mpd_client_get_period_index (mpdclient);
assert_equals_uint64 (periodIndex, 1);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling Period selection based on time
*
*/
GST_START_TEST (dash_mpdparser_get_period_at_time)
{
guint periodIndex;
GstDateTime *time;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M1DT1H4M3S\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\"></Period>"
" <Period id=\"Period1\"></Period>"
" <Period id=\"Period2\" start=\"P0Y0M1DT1H3M3S\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* request period for a time before availabilityStartTime, expect period index 0 */
time = gst_date_time_new_from_iso8601_string ("2015-03-23T23:30:59Z");
periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
gst_date_time_unref (time);
assert_equals_int (periodIndex, 0);
/* request period for a time from period 0 */
time = gst_date_time_new_from_iso8601_string ("2015-03-24T23:30:59Z");
periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
gst_date_time_unref (time);
assert_equals_int (periodIndex, 0);
/* request period for a time from period 1 */
time = gst_date_time_new_from_iso8601_string ("2015-03-25T1:1:1Z");
periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
gst_date_time_unref (time);
assert_equals_int (periodIndex, 1);
/* request period for a time from period 2 */
time = gst_date_time_new_from_iso8601_string ("2015-03-25T1:3:3Z");
periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
gst_date_time_unref (time);
assert_equals_int (periodIndex, 2);
/* request period for a time after mediaPresentationDuration, expect period index G_MAXUINT */
time = gst_date_time_new_from_iso8601_string ("2015-03-25T1:4:3Z");
periodIndex = gst_mpd_client_get_period_index_at_time (mpdclient, time);
gst_date_time_unref (time);
assert_equals_int (periodIndex, G_MAXUINT);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling Adaptation sets
*
*/
GST_START_TEST (dash_mpdparser_adaptationSet_handling)
{
const gchar *periodName;
guint adaptation_sets_count;
GList *adaptationSets, *it;
guint count = 0;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\"></AdaptationSet>"
" </Period>"
" <Period id=\"Period1\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"10\"></AdaptationSet>"
" <AdaptationSet id=\"11\"></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* period0 has 1 adaptation set */
fail_unless (mpdclient->periods != NULL);
periodName = gst_mpd_client_get_period_id (mpdclient);
assert_equals_string (periodName, "Period0");
adaptation_sets_count = gst_mpd_client_get_nb_adaptationSet (mpdclient);
assert_equals_int (adaptation_sets_count, 1);
/* period1 has 2 adaptation set */
ret = gst_mpd_client_set_period_id (mpdclient, "Period1");
assert_equals_int (ret, TRUE);
adaptation_sets_count = gst_mpd_client_get_nb_adaptationSet (mpdclient);
assert_equals_int (adaptation_sets_count, 2);
/* check the id for the 2 adaptation sets from period 1 */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
for (it = adaptationSets; it; it = g_list_next (it)) {
GstMPDAdaptationSetNode *adapt_set;
adapt_set = (GstMPDAdaptationSetNode *) it->data;
fail_if (adapt_set == NULL);
assert_equals_int (adapt_set->id, 10 + count);
count++;
}
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling Representation selection
*
*/
GST_START_TEST (dash_mpdparser_representation_selection)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adaptationSetNode;
GList *representations;
gint represendationIndex;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"video/mp4\">"
" <Representation id=\"v0\" bandwidth=\"500000\"></Representation>"
" <Representation id=\"v1\" bandwidth=\"250000\"></Representation>"
" </AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
adaptationSetNode = adaptationSets->data;
fail_if (adaptationSetNode == NULL);
assert_equals_int (adaptationSetNode->id, 1);
representations = adaptationSetNode->Representations;
fail_if (representations == NULL);
represendationIndex =
gst_mpd_client_get_rep_idx_with_min_bandwidth (representations);
assert_equals_int (represendationIndex, 1);
represendationIndex =
gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 0, 0, 0,
0, 1);
assert_equals_int (represendationIndex, 1);
represendationIndex =
gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 100000, 0,
2016-08-26 17:12:21 +00:00
0, 0, 1);
assert_equals_int (represendationIndex, -1);
represendationIndex =
gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 300000, 0,
2016-08-26 17:12:21 +00:00
0, 0, 1);
assert_equals_int (represendationIndex, 1);
represendationIndex =
gst_mpd_client_get_rep_idx_with_max_bandwidth (representations, 500000, 0,
2016-08-26 17:12:21 +00:00
0, 0, 1);
assert_equals_int (represendationIndex, 0);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling Active stream selection
*
*/
GST_START_TEST (dash_mpdparser_activeStream_selection)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
guint activeStreams;
GstActiveStream *activeStream;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation>"
" </AdaptationSet>"
" <AdaptationSet id=\"2\" mimeType=\"audio\">"
" <Representation id=\"2\" bandwidth=\"250000\">"
" </Representation>"
" </AdaptationSet>"
" <AdaptationSet id=\"3\" mimeType=\"application\">"
" <Representation id=\"3\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* no active streams yet */
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, 0);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* 1 active streams */
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, 1);
/* setup streaming from the second adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 1);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* 2 active streams */
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, 2);
/* setup streaming from the third adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 2);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* 3 active streams */
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, 3);
/* get details of the first active stream */
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
assert_equals_int (activeStream->mimeType, GST_STREAM_VIDEO);
/* get details of the second active stream */
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 1);
fail_if (activeStream == NULL);
assert_equals_int (activeStream->mimeType, GST_STREAM_AUDIO);
/* get details of the third active stream */
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 2);
fail_if (activeStream == NULL);
assert_equals_int (activeStream->mimeType, GST_STREAM_APPLICATION);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test getting Active stream parameters
*
*/
GST_START_TEST (dash_mpdparser_activeStream_parameters)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
guint activeStreams;
GstActiveStream *activeStream;
GstCaps *caps;
GstStructure *s;
gboolean bitstreamSwitchingFlag;
guint videoStreamWidth;
guint videoStreamHeight;
guint audioStreamRate;
guint audioChannelsCount;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\""
" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\""
" mimeType=\"video/mp4\""
" width=\"320\""
" height=\"240\""
" bitstreamSwitching=\"true\""
" audioSamplingRate=\"48000\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* 1 active streams */
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, 1);
/* get details of the first active stream */
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
assert_equals_int (activeStream->mimeType, GST_STREAM_VIDEO);
caps = gst_mpd_client_get_stream_caps (activeStream);
fail_unless (caps != NULL);
s = gst_caps_get_structure (caps, 0);
assert_equals_string (gst_structure_get_name (s), "video/quicktime");
gst_caps_unref (caps);
bitstreamSwitchingFlag =
gst_mpd_client_get_bitstream_switching_flag (activeStream);
assert_equals_int (bitstreamSwitchingFlag, 1);
videoStreamWidth = gst_mpd_client_get_video_stream_width (activeStream);
assert_equals_int (videoStreamWidth, 320);
videoStreamHeight = gst_mpd_client_get_video_stream_height (activeStream);
assert_equals_int (videoStreamHeight, 240);
audioStreamRate = gst_mpd_client_get_audio_stream_rate (activeStream);
assert_equals_int (audioStreamRate, 48000);
audioChannelsCount =
gst_mpd_client_get_audio_stream_num_channels (activeStream);
assert_equals_int (audioChannelsCount, 0);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test getting number and list of audio languages
*
*/
GST_START_TEST (dash_mpdparser_get_audio_languages)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
guint activeStreams;
guint adaptationSetsCount;
GList *languages = NULL;
guint languagesCount;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation>"
" </AdaptationSet>"
" <AdaptationSet id=\"2\" mimeType=\"video/mp4\">"
" <Representation id=\"2\" bandwidth=\"250000\">"
" </Representation>"
" </AdaptationSet>"
" <AdaptationSet id=\"3\" mimeType=\"audio\" lang=\"fr\">"
" <Representation id=\"3\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
gint i;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from all adaptation sets */
adaptationSetsCount = gst_mpd_client_get_nb_adaptationSet (mpdclient);
for (i = 0; i < adaptationSetsCount; i++) {
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, i);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
}
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, adaptationSetsCount);
languagesCount =
gst_mpd_client_get_list_and_nb_of_audio_language (mpdclient, &languages);
assert_equals_int (languagesCount, 2);
assert_equals_string ((gchar *) g_list_nth_data (languages, 0), "en");
assert_equals_string ((gchar *) g_list_nth_data (languages, 1), "fr");
g_list_free (languages);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Tests getting the base URL
*
*/
static GstMPDClient *
setup_mpd_client (const gchar * xml)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
guint activeStreams;
guint adaptationSetsCount;
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
gint i;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from all adaptation sets */
adaptationSetsCount = gst_mpd_client_get_nb_adaptationSet (mpdclient);
for (i = 0; i < adaptationSetsCount; i++) {
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, i);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
}
activeStreams = gst_mpd_client_get_nb_active_stream (mpdclient);
assert_equals_int (activeStreams, adaptationSetsCount);
return mpdclient;
}
GST_START_TEST (dash_mpdparser_get_baseURL1)
{
const gchar *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL>http://example.com/</BaseURL>"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL, "http://example.com/");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
GST_START_TEST (dash_mpdparser_get_baseURL2)
{
const gchar *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL>mpd_base_url/</BaseURL>"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <BaseURL> /period_base_url/</BaseURL>"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <BaseURL>adaptation_base_url</BaseURL>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <BaseURL>representation_base_url</BaseURL>"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
/* test baseURL. Its value should be computed like this:
* - start with xml url (null)
* - set it to the value from MPD's BaseURL element: "mpd_base_url/"
* - update the value with BaseURL element from Period. Because Period's
* baseURL is absolute (starts with /) it will overwrite the current value
* for baseURL. So, baseURL becomes "/period_base_url/"
* - update the value with BaseURL element from AdaptationSet. Because this
* is a relative url, it will update the current value. baseURL becomes
* "/period_base_url/adaptation_base_url"
* - update the value with BaseURL element from Representation. Because this
* is a relative url, it will update the current value. Because the current
* value does not end in /, everything after the last / will be overwritten.
* baseURL becomes "/period_base_url/representation_base_url"
*/
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL, "/period_base_url/representation_base_url");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
GST_START_TEST (dash_mpdparser_get_baseURL3)
{
const gchar *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL>mpd_base_url/</BaseURL>"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <BaseURL> /period_base_url/</BaseURL>"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <BaseURL>adaptation_base_url</BaseURL>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <BaseURL>/representation_base_url</BaseURL>"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
/* test baseURL. Its value should be computed like this:
* - start with xml url (null)
* - set it to the value from MPD's BaseURL element: "mpd_base_url/"
* - update the value with BaseURL element from Period. Because Period's
* baseURL is absolute (starts with /) it will overwrite the current value
* for baseURL. So, baseURL becomes "/period_base_url/"
* - update the value with BaseURL element from AdaptationSet. Because this
* is a relative url, it will update the current value. baseURL becomes
* "/period_base_url/adaptation_base_url"
* - update the value with BaseURL element from Representation. Because this
* is an absolute url, it will replace everything again"
*/
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL, "/representation_base_url");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
GST_START_TEST (dash_mpdparser_get_baseURL4)
{
const gchar *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL>mpd_base_url/</BaseURL>"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <BaseURL> /period_base_url/</BaseURL>"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <BaseURL>adaptation_base_url/</BaseURL>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <BaseURL>representation_base_url/</BaseURL>"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
/* test baseURL. Its value should be computed like this:
* - start with xml url (null)
* - set it to the value from MPD's BaseURL element: "mpd_base_url/"
* - update the value with BaseURL element from Period. Because Period's
* baseURL is absolute (starts with /) it will overwrite the current value
* for baseURL. So, baseURL becomes "/period_base_url/"
* - update the value with BaseURL element from AdaptationSet. Because this
* is a relative url, it will update the current value. baseURL becomes
* "/period_base_url/adaptation_base_url/"
* - update the value with BaseURL element from Representation. Because this
* is an relative url, it will update the current value."
*/
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL,
"/period_base_url/adaptation_base_url/representation_base_url/");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/* test multiple BaseUrl entries per section */
GST_START_TEST (dash_mpdparser_get_baseURL5)
{
GstMPDPeriodNode *periodNode;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
const gchar *baseURL;
GstMPDBaseURLNode *gstBaseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL>/mpd_base_url1/</BaseURL>"
" <BaseURL>/mpd_base_url2/</BaseURL>"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <BaseURL> period_base_url1/</BaseURL>"
" <BaseURL> period_base_url2/</BaseURL>"
" <BaseURL> period_base_url3/</BaseURL>"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <BaseURL>adaptation_base_url1/</BaseURL>"
" <BaseURL>adaptation_base_url2/</BaseURL>"
" <BaseURL>adaptation_base_url3/</BaseURL>"
" <BaseURL>adaptation_base_url4/</BaseURL>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <BaseURL>representation_base_url1/</BaseURL>"
" <BaseURL>representation_base_url2/</BaseURL>"
" <BaseURL>representation_base_url3/</BaseURL>"
" <BaseURL>representation_base_url4/</BaseURL>"
" <BaseURL>representation_base_url5/</BaseURL>"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
assert_equals_int (g_list_length (mpdclient->mpd_root_node->BaseURLs), 2);
gstBaseURL = g_list_nth_data (mpdclient->mpd_root_node->BaseURLs, 0);
assert_equals_string (gstBaseURL->baseURL, "/mpd_base_url1/");
gstBaseURL = g_list_nth_data (mpdclient->mpd_root_node->BaseURLs, 1);
assert_equals_string (gstBaseURL->baseURL, "/mpd_base_url2/");
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
assert_equals_int (g_list_length (periodNode->BaseURLs), 3);
gstBaseURL = g_list_nth_data (periodNode->BaseURLs, 0);
assert_equals_string (gstBaseURL->baseURL, " period_base_url1/");
gstBaseURL = g_list_nth_data (periodNode->BaseURLs, 1);
assert_equals_string (gstBaseURL->baseURL, " period_base_url2/");
gstBaseURL = g_list_nth_data (periodNode->BaseURLs, 2);
assert_equals_string (gstBaseURL->baseURL, " period_base_url3/");
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
assert_equals_int (g_list_length (adaptationSet->BaseURLs), 4);
gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 0);
assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url1/");
gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 1);
assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url2/");
gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 2);
assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url3/");
gstBaseURL = g_list_nth_data (adaptationSet->BaseURLs, 3);
assert_equals_string (gstBaseURL->baseURL, "adaptation_base_url4/");
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
assert_equals_int (g_list_length (representation->BaseURLs), 5);
gstBaseURL = g_list_nth_data (representation->BaseURLs, 0);
assert_equals_string (gstBaseURL->baseURL, "representation_base_url1/");
gstBaseURL = g_list_nth_data (representation->BaseURLs, 1);
assert_equals_string (gstBaseURL->baseURL, "representation_base_url2/");
gstBaseURL = g_list_nth_data (representation->BaseURLs, 2);
assert_equals_string (gstBaseURL->baseURL, "representation_base_url3/");
gstBaseURL = g_list_nth_data (representation->BaseURLs, 3);
assert_equals_string (gstBaseURL->baseURL, "representation_base_url4/");
gstBaseURL = g_list_nth_data (representation->BaseURLs, 4);
assert_equals_string (gstBaseURL->baseURL, "representation_base_url5/");
/* test baseURL. Its value should be computed like this:
* - start with xml url (null)
* - set it to the value from MPD's BaseURL element: "/mpd_base_url1/"
* - update the value with BaseURL element from Period. Because this
* is a relative url, it will update the current value. baseURL becomes
* "/mpd_base_url1/period_base_url1/"
* - update the value with BaseURL element from AdaptationSet. Because this
* is a relative url, it will update the current value. baseURL becomes
* "/mpd_base_url1/period_base_url1/adaptation_base_url1/"
* - update the value with BaseURL element from Representation. Because this
* is an relative url, it will update the current value."
*/
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL,
"/mpd_base_url1/period_base_url1/adaptation_base_url1/representation_base_url1/");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/* test no BaseURL */
GST_START_TEST (dash_mpdparser_get_baseURL6)
{
const gchar *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL, "");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/* BaseURL: test that the path is made absolute (a / is prepended if needed */
GST_START_TEST (dash_mpdparser_get_baseURL7)
{
const gchar *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL>x/example.com/</BaseURL>"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient;
mpdclient = setup_mpd_client (xml);
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL, "/x/example.com/");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/* BaseURL: test that a / is not prepended if the string contains ':'
* This tests uris with schema present */
GST_START_TEST (dash_mpdparser_get_baseURL8)
{
const gchar *baseURL;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <BaseURL>x:y/example.com/</BaseURL>"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
baseURL = gst_mpd_client_get_baseURL (mpdclient, 0);
fail_if (baseURL == NULL);
assert_equals_string (baseURL, "x:y/example.com/");
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test getting baseURL with query
*
*/
GST_START_TEST (dash_mpdparser_get_baseURL_with_query)
{
gboolean ret;
gchar *uri;
gint64 range_start, range_end;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period id=\"Period0\" duration=\"P0Y0M1DT1H1M1S\">"
" <AdaptationSet id=\"1\" mimeType=\"audio\" lang=\"en\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <BaseURL>http://example.com/test?param1=value1&amp;param2=value2</BaseURL>"
" <SegmentBase indexRange=\"100-200\" indexRangeExact=\"true\">"
" <Initialization range=\"0-100\" />"
" </SegmentBase>"
" </Representation></AdaptationSet></Period></MPD>";
GstMPDClient *mpdclient = setup_mpd_client (xml);
/* get segment url and range from segment Initialization */
ret =
gst_mpd_client_get_next_header (mpdclient, &uri, 0, &range_start,
&range_end);
assert_equals_int (ret, TRUE);
assert_equals_string (uri,
"http://example.com/test?param1=value1&param2=value2");
assert_equals_int64 (range_start, 0);
assert_equals_int64 (range_end, 100);
g_free (uri);
/* get segment url and range from segment indexRange */
ret =
gst_mpd_client_get_next_header_index (mpdclient, &uri, 0, &range_start,
&range_end);
assert_equals_int (ret, TRUE);
assert_equals_string (uri,
"http://example.com/test?param1=value1&param2=value2");
assert_equals_int64 (range_start, 100);
assert_equals_int64 (range_end, 200);
g_free (uri);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test getting mediaPresentationDuration
*
*/
GST_START_TEST (dash_mpdparser_get_mediaPresentationDuration)
{
GstClockTime mediaPresentationDuration;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" mediaPresentationDuration=\"P0Y0M0DT0H0M3S\"></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
mediaPresentationDuration =
gst_mpd_client_get_media_presentation_duration (mpdclient);
assert_equals_uint64 (mediaPresentationDuration, 3000000000);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test getting streamPresentationOffset
*
*/
GST_START_TEST (dash_mpdparser_get_streamPresentationOffset)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstClockTime offset;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period>"
" <AdaptationSet mimeType=\"video/mp4\">"
" <SegmentBase timescale=\"1000\" presentationTimeOffset=\"3000\">"
" </SegmentBase>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* test the stream presentation time offset */
offset = gst_mpd_client_get_stream_presentation_offset (mpdclient, 0);
/* seems to be set only for template segments, so here it is 0 */
assert_equals_int (offset, 0);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling segments
*
*/
GST_START_TEST (dash_mpdparser_segments)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
gboolean hasNextSegment;
GstActiveStream *activeStream;
GstFlowReturn flow;
GstDateTime *segmentAvailability;
GstDateTime *gst_time;
GDateTime *g_time;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" type=\"dynamic\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period id=\"Period0\" start=\"P0Y0M0DT0H0M10S\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList duration=\"45\">"
" <SegmentURL media=\"TestMedia1\""
" mediaRange=\"10-20\""
" index=\"TestIndex1\""
" indexRange=\"30-40\">"
" </SegmentURL>"
" <SegmentURL media=\"TestMedia2\""
" mediaRange=\"20-30\""
" index=\"TestIndex2\""
" indexRange=\"40-50\">"
" </SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
/* segment_index 0, segment_count 2.
* Has next segment and can advance to next segment
*/
hasNextSegment =
gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
assert_equals_int (hasNextSegment, 1);
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_OK);
/* segment_index 1, segment_count 2.
* Does not have next segment and can not advance to next segment
*/
hasNextSegment =
gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
assert_equals_int (hasNextSegment, 0);
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_EOS);
/* go to first segment */
gst_mpd_client_seek_to_first_segment (mpdclient);
/* segment_index 0, segment_count 2.
* Has next segment and can advance to next segment
*/
hasNextSegment =
gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
assert_equals_int (hasNextSegment, 1);
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_OK);
/* segment_index 1, segment_count 2
* Does not have next segment
*/
hasNextSegment =
gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
assert_equals_int (hasNextSegment, 0);
/* segment index is still 1 */
hasNextSegment =
gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
assert_equals_int (hasNextSegment, 0);
/* each segment has a duration of 0 hours, 0 min 45 seconds
* segment index is 1.
* Start time is at the beginning of segment 1, so 1 * segment_duration = 1 * 45s
* Availability start time is at the end of the segment, so we add duration (45s)
* We also add period start time (10s)
* So, availability start time for segment 1 is: 10 (period start) +
* 45 (segment start) + 45 (duration) = 1'40s
*/
segmentAvailability =
gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
activeStream);
assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
assert_equals_int (gst_date_time_get_minute (segmentAvailability), 1);
assert_equals_int (gst_date_time_get_second (segmentAvailability), 40);
gst_date_time_unref (segmentAvailability);
/* seek to time */
gst_time = gst_date_time_new_from_iso8601_string ("2015-03-24T0:0:20Z");
g_time = gst_date_time_to_g_date_time (gst_time);
ret = gst_mpd_client_seek_to_time (mpdclient, g_time);
assert_equals_int (ret, 1);
gst_date_time_unref (gst_time);
g_date_time_unref (g_time);
/* segment index is now 0 */
hasNextSegment =
gst_mpd_client_has_next_segment (mpdclient, activeStream, TRUE);
assert_equals_int (hasNextSegment, 1);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling headers
*
*/
GST_START_TEST (dash_mpdparser_headers)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
gchar *uri;
gint64 range_start;
gint64 range_end;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" type=\"dynamic\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period id=\"Period0\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentBase indexRange=\"10-20\">"
" <Initialization sourceURL=\"TestSourceUrl\""
" range=\"100-200\">"
" </Initialization>"
" <RepresentationIndex sourceURL=\"TestSourceIndex\">"
" </RepresentationIndex>"
" </SegmentBase>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
/* get segment url and range from segment Initialization */
ret =
gst_mpd_client_get_next_header (mpdclient, &uri, 0, &range_start,
&range_end);
assert_equals_int (ret, TRUE);
assert_equals_string (uri, "TestSourceUrl");
assert_equals_int64 (range_start, 100);
assert_equals_int64 (range_end, 200);
g_free (uri);
/* get segment url and range from segment indexRange */
ret =
gst_mpd_client_get_next_header_index (mpdclient, &uri, 0, &range_start,
&range_end);
assert_equals_int (ret, TRUE);
assert_equals_string (uri, "TestSourceIndex");
assert_equals_int64 (range_start, 10);
assert_equals_int64 (range_end, 20);
g_free (uri);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling fragments
*
*/
GST_START_TEST (dash_mpdparser_fragments)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstMediaFragmentInfo fragment;
GstActiveStream *activeStream;
GstClockTime nextFragmentDuration;
GstClockTime nextFragmentTimestamp;
GstClockTime nextFragmentTimestampEnd;
GstClockTime periodStartTime;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
GstClockTime expectedTimestampEnd;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period id=\"Period0\" start=\"P0Y0M0DT0H0M10S\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
/* expected duration of the next fragment */
expectedDuration = duration_to_ms (0, 0, 0, 3, 3, 20, 0);
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
expectedTimestampEnd = duration_to_ms (0, 0, 0, 3, 3, 20, 0);
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "");
assert_equals_int64 (fragment.range_start, 0);
assert_equals_int64 (fragment.range_end, -1);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
periodStartTime = gst_mpd_client_get_period_start_time (mpdclient);
assert_equals_uint64 (periodStartTime, 10 * GST_SECOND);
nextFragmentDuration =
gst_mpd_client_get_next_fragment_duration (mpdclient, activeStream);
assert_equals_uint64 (nextFragmentDuration, expectedDuration * GST_MSECOND);
ret =
gst_mpd_client_get_next_fragment_timestamp (mpdclient, 0,
&nextFragmentTimestamp);
assert_equals_int (ret, TRUE);
assert_equals_uint64 (nextFragmentTimestamp, expectedTimestamp * GST_MSECOND);
ret =
gst_mpd_client_get_last_fragment_timestamp_end (mpdclient, 0,
&nextFragmentTimestampEnd);
assert_equals_int (ret, TRUE);
assert_equals_uint64 (nextFragmentTimestampEnd,
expectedTimestampEnd * GST_MSECOND);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test inheriting segmentBase from parent
*
*/
GST_START_TEST (dash_mpdparser_inherited_segmentBase)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentBaseNode *segmentBase;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <SegmentBase timescale=\"100\">"
" </SegmentBase>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentBase timescale=\"200\">"
" </SegmentBase>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
/* test segment base from adaptation set */
segmentBase = adaptationSet->SegmentBase;
assert_equals_uint64 (segmentBase->timescale, 100);
/* test segment base from representation */
segmentBase = representation->SegmentBase;
assert_equals_uint64 (segmentBase->timescale, 200);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test inheriting segmentURL from parent
*
*/
GST_START_TEST (dash_mpdparser_inherited_segmentURL)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstActiveStream *activeStream;
GstMediaFragmentInfo fragment;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
GstFlowReturn flow;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period>"
" <AdaptationSet mimeType=\"video/mp4\">"
" <SegmentList duration=\"100\">"
" <SegmentURL media=\"TestMediaAdaptation\""
" mediaRange=\"10-20\""
" index=\"TestIndexAdaptation\""
" indexRange=\"30-40\">"
" </SegmentURL>"
" </SegmentList>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList duration=\"110\">"
" <SegmentURL media=\"TestMediaRep\""
" mediaRange=\"100-200\""
" index=\"TestIndexRep\""
" indexRange=\"300-400\">"
" </SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
/* expected duration of the next fragment
* Segment duration was set to 100 in AdaptationSet and to 110 in Representation
* We expect duration to be 110
*/
expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 110, 0);
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
/* the representation contains 1 segment (the one from Representation) */
/* check first segment */
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMediaRep");
assert_equals_int64 (fragment.range_start, 100);
assert_equals_int64 (fragment.range_end, 200);
assert_equals_string (fragment.index_uri, "/TestIndexRep");
assert_equals_int64 (fragment.index_range_start, 300);
assert_equals_int64 (fragment.index_range_end, 400);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/* try to advance to next segment. Should fail */
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_EOS);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test segment list
*
*/
GST_START_TEST (dash_mpdparser_segment_list)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstActiveStream *activeStream;
GstMediaFragmentInfo fragment;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period start=\"P0Y0M0DT0H0M10S\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList duration=\"12000\">"
" <SegmentURL media=\"TestMedia\""
" mediaRange=\"100-200\""
" index=\"TestIndex\""
" indexRange=\"300-400\">"
" </SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
/* expected duration of the next fragment
* Segment duration was set larger than period duration (12000 vs 11000).
* We expect it to be limited to period duration.
*/
expectedDuration = duration_to_ms (0, 0, 0, 3, 3, 20, 0);
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 10, 0);
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMedia");
assert_equals_int64 (fragment.range_start, 100);
assert_equals_int64 (fragment.range_end, 200);
assert_equals_string (fragment.index_uri, "/TestIndex");
assert_equals_int64 (fragment.index_range_start, 300);
assert_equals_int64 (fragment.index_range_end, 400);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test segment template
*
*/
GST_START_TEST (dash_mpdparser_segment_template)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstActiveStream *activeStream;
GstMediaFragmentInfo fragment;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
GstClockTime periodStartTime;
GstClockTime offset;
GstClockTime lastFragmentTimestampEnd;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period start=\"P0Y0M0DT0H0M10S\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <Representation id=\"repId\" bandwidth=\"250000\">"
" <SegmentTemplate duration=\"12000\""
" presentationTimeOffset=\"15\""
" media=\"TestMedia_rep=$RepresentationID$number=$Number$bandwidth=$Bandwidth$time=$Time$\""
" index=\"TestIndex\">"
" </SegmentTemplate>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
/* expected duration of the next fragment
* Segment duration was set larger than period duration (12000 vs 11000).
* We expect it to not be limited to period duration.
*/
expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 12000, 0);
/* while the period starts at 10ms, the fragment timestamp is supposed to be
* 0ms. timestamps are starting from 0 at every period, and only the overall
* composition of periods should consider the period start timestamp. In
* dashdemux this is done by mapping the 0 fragment timestamp to a stream
* time equal to the period start time.
*/
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri,
"/TestMedia_rep=repIdnumber=1bandwidth=250000time=0");
assert_equals_int64 (fragment.range_start, 0);
assert_equals_int64 (fragment.range_end, -1);
assert_equals_string (fragment.index_uri, "/TestIndex");
assert_equals_int64 (fragment.index_range_start, 0);
assert_equals_int64 (fragment.index_range_end, -1);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
periodStartTime = gst_mpd_client_get_period_start_time (mpdclient);
assert_equals_uint64 (periodStartTime, 10 * GST_SECOND);
offset = gst_mpd_client_get_stream_presentation_offset (mpdclient, 0);
assert_equals_uint64 (offset, 15 * GST_SECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/*
* Period starts at 10s.
* MPD has a duration of 3h3m30s, so period duration is 3h3m20s.
* We expect the last fragment to end at period start + period duration: 3h3m30s
*/
expectedTimestamp = duration_to_ms (0, 0, 0, 3, 3, 30, 0);
gst_mpd_client_get_last_fragment_timestamp_end (mpdclient, 0,
&lastFragmentTimestampEnd);
assert_equals_uint64 (lastFragmentTimestampEnd,
expectedTimestamp * GST_MSECOND);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test segment timeline
*
*/
GST_START_TEST (dash_mpdparser_segment_timeline)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstActiveStream *activeStream;
GstMediaFragmentInfo fragment;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
GstFlowReturn flow;
GstDateTime *segmentAvailability;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period start=\"P0Y0M0DT0H0M10S\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <SegmentList>"
" <SegmentTimeline>"
" <S t=\"10\" d=\"20\" r=\"30\"></S>"
" </SegmentTimeline>"
" </SegmentList>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList>"
" <SegmentTimeline>"
" <S t=\"3\" d=\"2\" r=\"1\"></S>"
" <S t=\"10\" d=\"3\" r=\"0\"></S>"
" </SegmentTimeline>"
" <SegmentURL media=\"TestMedia0\""
" index=\"TestIndex0\">"
" </SegmentURL>"
" <SegmentURL media=\"TestMedia1\""
" index=\"TestIndex1\">"
" </SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
/* expected duration of the next fragment */
expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 2, 0);
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 13, 0);
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMedia0");
assert_equals_string (fragment.index_uri, "/TestIndex0");
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/* first segment starts at 3s and has a duration of 2s.
* We also add period start time (10s) so we expect a segment availability
* start time of 15s
*/
segmentAvailability =
gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
activeStream);
fail_unless (segmentAvailability != NULL);
assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
assert_equals_int (gst_date_time_get_minute (segmentAvailability), 0);
assert_equals_int (gst_date_time_get_second (segmentAvailability), 15);
gst_date_time_unref (segmentAvailability);
/* advance to next segment */
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_OK);
/* second segment starts after first ends */
expectedTimestamp = expectedTimestamp + expectedDuration;
/* check second segment.
* It is a repeat of first segmentURL, because "r" in SegmentTimeline is 1
*/
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMedia0");
assert_equals_string (fragment.index_uri, "/TestIndex0");
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/* first segment starts at 3s and has a duration of 2s.
* Second segment starts when the first ends (5s) and has a duration of 2s,
* so it ends at 7s.
* We also add period start time (10s) so we expect a segment availability
* start time of 17s
*/
segmentAvailability =
gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
activeStream);
fail_unless (segmentAvailability != NULL);
assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
assert_equals_int (gst_date_time_get_minute (segmentAvailability), 0);
assert_equals_int (gst_date_time_get_second (segmentAvailability), 17);
gst_date_time_unref (segmentAvailability);
/* advance to next segment */
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_OK);
/* third segment has a small gap after the second ends (t=10) */
expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 3, 0);
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 20, 0);
/* check third segment */
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMedia1");
assert_equals_string (fragment.index_uri, "/TestIndex1");
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/* Third segment starts at 10s and has a duration of 3s so it ends at 13s.
* We also add period start time (10s) so we expect a segment availability
* start time of 23s
*/
segmentAvailability =
gst_mpd_client_get_next_segment_availability_start_time (mpdclient,
activeStream);
fail_unless (segmentAvailability != NULL);
assert_equals_int (gst_date_time_get_year (segmentAvailability), 2015);
assert_equals_int (gst_date_time_get_month (segmentAvailability), 3);
assert_equals_int (gst_date_time_get_day (segmentAvailability), 24);
assert_equals_int (gst_date_time_get_hour (segmentAvailability), 0);
assert_equals_int (gst_date_time_get_minute (segmentAvailability), 0);
assert_equals_int (gst_date_time_get_second (segmentAvailability), 23);
gst_date_time_unref (segmentAvailability);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test SegmentList with multiple inherited segmentURLs
*
*/
GST_START_TEST (dash_mpdparser_multiple_inherited_segmentURL)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstActiveStream *activeStream;
GstMediaFragmentInfo fragment;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
GstFlowReturn flow;
/*
* Period duration is 30 seconds
* Period start is 10 seconds. Thus, period duration is 20 seconds.
*
* There are 2 segments in the AdaptationSet segment list and 2 in the
* Representation's segment list.
* Segment duration is 5s for the Adaptation segments and 8s for
* Representation segments.
* Separately, each segment list (duration 2*5=10 or 2*8=16) fits comfortably
* in the Period's 20s duration.
*
* We expect the Representation segments to overwrite the AdaptationSet segments.
*/
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT0H0M30S\">"
"<Period>"
" <AdaptationSet mimeType=\"video/mp4\">"
" <SegmentList duration=\"5\">"
" <SegmentURL"
" media=\"TestMedia0\" mediaRange=\"10-20\""
" index=\"TestIndex0\" indexRange=\"100-200\""
" ></SegmentURL>"
" <SegmentURL"
" media=\"TestMedia1\" mediaRange=\"20-30\""
" index=\"TestIndex1\" indexRange=\"200-300\""
" ></SegmentURL>"
" </SegmentList>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList duration=\"8\">"
" <SegmentURL"
" media=\"TestMedia2\" mediaRange=\"30-40\""
" index=\"TestIndex2\" indexRange=\"300-400\""
" ></SegmentURL>"
" <SegmentURL"
" media=\"TestMedia3\" mediaRange=\"40-50\""
" index=\"TestIndex3\" indexRange=\"400-500\""
" ></SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 8, 0);
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 0, 0);
/* the representation contains 2 segments defined in the Representation
*
* Both will have the duration specified in the Representation (8)
*/
/* check first segment */
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMedia2");
assert_equals_int64 (fragment.range_start, 30);
assert_equals_int64 (fragment.range_end, 40);
assert_equals_string (fragment.index_uri, "/TestIndex2");
assert_equals_int64 (fragment.index_range_start, 300);
assert_equals_int64 (fragment.index_range_end, 400);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/* advance to next segment */
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_OK);
/* second segment starts after previous ends */
expectedTimestamp = expectedTimestamp + expectedDuration;
/* check second segment */
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMedia3");
assert_equals_int64 (fragment.range_start, 40);
assert_equals_int64 (fragment.range_end, 50);
assert_equals_string (fragment.index_uri, "/TestIndex3");
assert_equals_int64 (fragment.index_range_start, 400);
assert_equals_int64 (fragment.index_range_end, 500);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/* try to advance to the next segment. There isn't any, so it should fail */
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_EOS);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test SegmentList with multiple segmentURL
*
*/
GST_START_TEST (dash_mpdparser_multipleSegmentURL)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
GstActiveStream *activeStream;
GstMediaFragmentInfo fragment;
GstClockTime expectedDuration;
GstClockTime expectedTimestamp;
GstFlowReturn flow;
/*
* Period duration is 30 seconds
* Period start is 10 seconds. Thus, period duration is 20 seconds.
*
* Segment duration is 25 seconds. There are 2 segments in the list.
* We expect first segment to have a duration of 20 seconds (limited by the period)
* and the second segment to not exist.
*/
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT0H0M30S\">"
"<Period start=\"P0Y0M0DT0H0M10S\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList duration=\"25\">"
" <SegmentURL"
" media=\"TestMedia0\" mediaRange=\"10-20\""
" index=\"TestIndex0\" indexRange=\"100-200\""
" ></SegmentURL>"
" <SegmentURL"
" media=\"TestMedia1\" mediaRange=\"20-30\""
" index=\"TestIndex1\" indexRange=\"200-300\""
" ></SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
/* setup streaming from the first adaptation set */
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, TRUE);
activeStream = gst_mpd_client_get_active_stream_by_index (mpdclient, 0);
fail_if (activeStream == NULL);
expectedDuration = duration_to_ms (0, 0, 0, 0, 0, 20, 0);
expectedTimestamp = duration_to_ms (0, 0, 0, 0, 0, 10, 0);
/* the representation contains 2 segments. The first is partially
* clipped, and the second entirely (and thus discarded).
*/
/* check first segment */
ret = gst_mpd_client_get_next_fragment (mpdclient, 0, &fragment);
assert_equals_int (ret, TRUE);
assert_equals_string (fragment.uri, "/TestMedia0");
assert_equals_int64 (fragment.range_start, 10);
assert_equals_int64 (fragment.range_end, 20);
assert_equals_string (fragment.index_uri, "/TestIndex0");
assert_equals_int64 (fragment.index_range_start, 100);
assert_equals_int64 (fragment.index_range_end, 200);
assert_equals_uint64 (fragment.duration, expectedDuration * GST_MSECOND);
assert_equals_uint64 (fragment.timestamp, expectedTimestamp * GST_MSECOND);
gst_mpdparser_media_fragment_info_clear (&fragment);
/* advance to next segment */
flow = gst_mpd_client_advance_segment (mpdclient, activeStream, TRUE);
assert_equals_int (flow, GST_FLOW_EOS);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing empty xml string
*
*/
GST_START_TEST (dash_mpdparser_missing_xml)
{
const gchar *xml = "";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing an xml with no mpd tag
*
*/
GST_START_TEST (dash_mpdparser_missing_mpd)
{
const gchar *xml = "<?xml version=\"1.0\"?>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing an MPD with a wrong end tag
*/
GST_START_TEST (dash_mpdparser_no_end_tag)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"> </NPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing an MPD with no default namespace
*/
GST_START_TEST (dash_mpdparser_no_default_namespace)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD profiles=\"urn:mpeg:dash:profile:isoff-main:2011\"></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, strlen (xml));
assert_equals_int (ret, TRUE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling wrong period duration during attempts to
* infer a period duration from the start time of the next period
*/
GST_START_TEST (dash_mpdparser_wrong_period_duration_inferred_from_next_period)
{
const gchar *periodName;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period id=\"Period0\" duration=\"P0Y0M0DT1H1M0S\"></Period>"
" <Period id=\"Period1\"></Period>"
" <Period id=\"Period2\" start=\"P0Y0M0DT0H0M10S\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* period_idx should be 0 and we should have no active periods */
assert_equals_uint64 (mpdclient->period_idx, 0);
fail_unless (mpdclient->periods == NULL);
/* process the xml data */
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* Period0 should be present */
fail_unless (mpdclient->periods != NULL);
periodName = gst_mpd_client_get_period_id (mpdclient);
assert_equals_string (periodName, "Period0");
/* Period1 should not be present due to wrong duration */
ret = gst_mpd_client_set_period_index (mpdclient, 1);
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test handling wrong period duration during attempts to
* infer a period duration from the mediaPresentationDuration
*/
GST_START_TEST
(dash_mpdparser_wrong_period_duration_inferred_from_next_mediaPresentationDuration)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period id=\"Period0\" start=\"P0Y0M0DT4H0M0S\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* period_idx should be 0 and we should have no active periods */
assert_equals_uint64 (mpdclient->period_idx, 0);
fail_unless (mpdclient->periods == NULL);
/* process the xml data
* should fail due to wrong duration in Period0 (start > mediaPresentationDuration)
*/
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
GST_START_TEST (dash_mpdparser_whitespace_strings)
{
fail_unless (_mpd_helper_validate_no_whitespace ("") == TRUE);
fail_unless (_mpd_helper_validate_no_whitespace ("/") == TRUE);
fail_unless (_mpd_helper_validate_no_whitespace (" ") == FALSE);
fail_unless (_mpd_helper_validate_no_whitespace ("aaaaaaaa ") == FALSE);
fail_unless (_mpd_helper_validate_no_whitespace ("a\ta") == FALSE);
fail_unless (_mpd_helper_validate_no_whitespace ("a\ra") == FALSE);
fail_unless (_mpd_helper_validate_no_whitespace ("a\na") == FALSE);
}
GST_END_TEST;
GST_START_TEST (dash_mpdparser_rfc1738_strings)
{
fail_unless (gst_mpdparser_validate_rfc1738_url ("/") == TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url (" ") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("aaaaaaaa ") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("") == TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("a") == TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url
(";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),%AA")
== TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url
(";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),/%AA")
== TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url
(";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),% ")
== FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%AA") == TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%A") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%XA") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%AX") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%XX") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("\001") == FALSE);
}
GST_END_TEST;
/*
* Test negative period duration
*/
GST_START_TEST (dash_mpdparser_negative_period_duration)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period id=\"Period0\""
" start=\"P0Y0M0DT1H0M0S\""
" duration=\"-PT10S\">"
" </Period><Period id=\"Period1\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data
* should fail due to negative duration of Period0
*/
ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing negative values from attributes that should be unsigned
*
*/
GST_START_TEST (dash_mpdparser_read_unsigned_from_negative_values)
{
GstMPDPeriodNode *periodNode;
GstMPDSegmentBaseNode *segmentBase;
GstMPDAdaptationSetNode *adaptationSet;
GstMPDRepresentationNode *representation;
GstMPDSubRepresentationNode *subRepresentation;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015--1-13T12:25:37\">"
" <Period start=\"-P-2015Y\" duration=\"-P-5M\">"
" <SegmentBase presentationTimeOffset=\"-10\""
" timescale=\"-5\""
" indexRange=\"1--10\">"
" </SegmentBase>"
" <AdaptationSet par=\"-1:7\""
" minFrameRate=\" -1\""
" segmentAlignment=\"-4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SubRepresentation dependencyLevel=\"1 -2 3\">"
" </SubRepresentation>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
periodNode = (GstMPDPeriodNode *) mpdclient->mpd_root_node->Periods->data;
segmentBase = periodNode->SegmentBase;
adaptationSet = (GstMPDAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstMPDRepresentationNode *)
adaptationSet->Representations->data;
subRepresentation = (GstMPDSubRepresentationNode *)
representation->SubRepresentations->data;
/* availabilityStartTime parsing should fail */
fail_if (mpdclient->mpd_root_node->availabilityStartTime != NULL);
/* Period start parsing should fail */
assert_equals_int64 (periodNode->start, -1);
/* Period duration parsing should fail */
assert_equals_int64 (periodNode->duration, -1);
/* expect negative value to be rejected and presentationTimeOffset to be 0 */
assert_equals_uint64 (segmentBase->presentationTimeOffset, 0);
assert_equals_uint64 (segmentBase->timescale, 1);
fail_if (segmentBase->indexRange != NULL);
/* par ratio parsing should fail */
fail_if (adaptationSet->par != NULL);
/* minFrameRate parsing should fail */
fail_if (GST_MPD_REPRESENTATION_BASE_NODE (adaptationSet)->minFrameRate !=
NULL);
/* segmentAlignment parsing should fail */
fail_if (adaptationSet->segmentAlignment != NULL);
/* dependency level parsing should fail */
fail_if (subRepresentation->dependencyLevel != NULL);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test negative mediaPresentationDuration duration
*/
GST_START_TEST (dash_mpdparser_negative_mediaPresentationDuration)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"-P0Y0M0DT3H3M30S\">"
" <Period id=\"Period0\" start=\"P0Y0M0DT1H0M0S\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data
* should fail due to negative duration of mediaPresentationDuration
*/
ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing an MPD with no profiles
*/
GST_START_TEST (dash_mpdparser_no_profiles)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\"></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, strlen (xml));
assert_equals_int (ret, TRUE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test S node list greater than SegmentURL list
*
*/
GST_START_TEST (dash_mpdparser_unmatched_segmentTimeline_segmentURL)
{
GList *adaptationSets;
GstMPDAdaptationSetNode *adapt_set;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" mediaPresentationDuration=\"P0Y0M0DT3H3M30S\">"
" <Period start=\"P0Y0M0DT0H0M10S\">"
" <AdaptationSet mimeType=\"video/mp4\">"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentList>"
" <SegmentTimeline>"
" <S t=\"3\" d=\"2\" r=\"1\"></S>"
" <S t=\"10\" d=\"3\" r=\"0\"></S>"
" </SegmentTimeline>"
" <SegmentURL media=\"TestMedia0\""
" index=\"TestIndex0\">"
" </SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
/* process the xml data */
ret = gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
/* get the list of adaptation sets of the first period */
adaptationSets = gst_mpd_client_get_adaptation_sets (mpdclient);
fail_if (adaptationSets == NULL);
adapt_set = (GstMPDAdaptationSetNode *) g_list_nth_data (adaptationSets, 0);
fail_if (adapt_set == NULL);
/* setup streaming from the first adaptation set.
* Should fail because the second S node does not have a matching
* SegmentURL node
*/
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set);
assert_equals_int (ret, FALSE);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test parsing of the default presentation delay property
*/
GST_START_TEST (dash_mpdparser_default_presentation_delay)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" maxSegmentDuration=\"PT2S\">"
" <Period id=\"Period0\" start=\"P0S\"></Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
gint64 value;
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "5s");
assert_equals_int64 (value, 5000);
value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "5S");
assert_equals_int64 (value, 5000);
value =
gst_mpd_client_parse_default_presentation_delay (mpdclient, "5 seconds");
assert_equals_int64 (value, 5000);
value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "2500ms");
assert_equals_int64 (value, 2500);
value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "3f");
assert_equals_int64 (value, 6000);
value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "3F");
assert_equals_int64 (value, 6000);
value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "");
assert_equals_int64 (value, 0);
value = gst_mpd_client_parse_default_presentation_delay (mpdclient, "10");
assert_equals_int64 (value, 0);
value =
gst_mpd_client_parse_default_presentation_delay (mpdclient,
"not a number");
assert_equals_int64 (value, 0);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
GST_START_TEST (dash_mpdparser_duration)
{
guint64 v;
fail_unless (_mpd_helper_parse_duration ("", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration (" ", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("0", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("D-1", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("T", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("PT", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("PX", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PPT", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PTT", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P1D", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("P1D1D", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P1D1M", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P1M1D", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("P1M1D1M", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P1M1D1D", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P0M0D", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("P-1M", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P15M", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P-1D", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P35D", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P-1Y", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT-1H", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT25H", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT-1M", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT65M", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT-1S", &v) == FALSE);
/* seconds are allowed to be larger than 60 */
fail_unless (_mpd_helper_parse_duration ("PT65S", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("PT1.1H", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT1-1H", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT1-H", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT-H", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PTH", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT0", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("PT1.1S", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("PT1.1.1S", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P585Y", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P584Y", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration (" P10DT8H", &v) == TRUE);
fail_unless (_mpd_helper_parse_duration ("P10D T8H", &v) == FALSE);
fail_unless (_mpd_helper_parse_duration ("P10DT8H ", &v) == TRUE);
}
GST_END_TEST;
/*
* Test that the maximum_segment_duration correctly implements the
* rules in the DASH specification
*/
GST_START_TEST (dash_mpdparser_maximum_segment_duration)
{
const gchar *xml_template =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" availabilityStartTime=\"2015-03-24T0:0:0\""
" %s "
" mediaPresentationDuration=\"P100Y\">"
" <Period id=\"Period0\" start=\"PT0S\">"
" <AdaptationSet mimeType=\"video/mp4\" >"
" <SegmentTemplate timescale=\"90000\" initialization=\"$RepresentationID$/Header.m4s\" media=\"$RepresentationID$/$Number$.m4s\" duration=\"360000\" />"
" <Representation id=\"video1\" width=\"576\" height=\"324\" frameRate=\"25\" sar=\"1:1\" bandwidth=\"900000\" codecs=\"avc1.4D401E\"/>"
" </AdaptationSet>"
" <AdaptationSet mimeType=\"audio/mp4\" >"
" <SegmentTemplate timescale=\"90000\" initialization=\"$RepresentationID$/Header.m4s\" media=\"$RepresentationID$/$Number$.m4s\" duration=\"340000\" />"
" <Representation id=\"audio1\" audioSamplingRate=\"22050\" bandwidth=\"29600\" codecs=\"mp4a.40.2\">"
" <AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"2\"/>"
" </Representation>" " </AdaptationSet>" " </Period></MPD>";
gboolean ret;
GstMPDClient *mpdclient;
gchar *xml;
GstClockTime dur;
GList *adapt_sets, *iter;
xml = g_strdup_printf (xml_template, "maxSegmentDuration=\"PT4.5S\"");
mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
g_free (xml);
assert_equals_int (ret, TRUE);
assert_equals_uint64 (mpdclient->mpd_root_node->maxSegmentDuration,
duration_to_ms (0, 0, 0, 0, 0, 4, 500));
dur = gst_mpd_client_get_maximum_segment_duration (mpdclient);
assert_equals_uint64 (dur, duration_to_clocktime (0, 0, 0, 0, 0, 4, 500));
gst_mpd_client_free (mpdclient);
/* now parse without the maxSegmentDuration attribute, to check that
gst_mpd_client_get_maximum_segment_duration uses the maximum
duration of any segment
*/
xml = g_strdup_printf (xml_template, "");
mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
g_free (xml);
assert_equals_int (ret, TRUE);
ret =
gst_mpd_client_setup_media_presentation (mpdclient, GST_CLOCK_TIME_NONE,
-1, NULL);
assert_equals_int (ret, TRUE);
adapt_sets = gst_mpd_client_get_adaptation_sets (mpdclient);
for (iter = adapt_sets; iter; iter = g_list_next (iter)) {
GstMPDAdaptationSetNode *adapt_set_node = iter->data;
ret = gst_mpd_client_setup_streaming (mpdclient, adapt_set_node);
assert_equals_int (ret, TRUE);
}
dur = gst_mpd_client_get_maximum_segment_duration (mpdclient);
assert_equals_uint64 (dur, duration_to_clocktime (0, 0, 0, 0, 0, 4, 0));
gst_mpd_client_free (mpdclient);
}
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)
{
GstMPDPeriodNode *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);
2019-09-02 19:08:44 +00:00
/* constructs initial mpd using external xml uri */
/* For invalid URI, mpdparser should be ignore it */
xml_joined = g_strjoin ("", xml_frag_start,
xml_uri_front, "http://404.invalid/ERROR/XML.period", xml_uri_rear,
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_client_parse (mpdclient, xml_joined, (gint) strlen (xml_joined));
assert_equals_int (ret, TRUE);
period_list = mpdclient->mpd_root_node->Periods;
/* only count periods on initial mpd (external xml does not parsed yet) */
assert_equals_int (g_list_length (period_list), 4);
/* 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_root_node->Periods;
assert_equals_int (g_list_length (period_list), 4);
iter = period_list;
periodNode = (GstMPDPeriodNode *) iter->data;
assert_equals_string (periodNode->id, "Period0");
iter = iter->next;
periodNode = (GstMPDPeriodNode *) iter->data;
assert_equals_string (periodNode->id, "xlink-single-period-Period1");
iter = iter->next;
periodNode = (GstMPDPeriodNode *) iter->data;
assert_equals_string (periodNode->id, "xlink-double-period-Period1");
iter = iter->next;
periodNode = (GstMPDPeriodNode *) 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;
/*
* Test parsing xsd:datetime with timezoneoffset.
*
*/
GST_START_TEST (dash_mpdparser_datetime_with_tz_offset)
{
GstDateTime *availabilityStartTime;
GstDateTime *availabilityEndTime;
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" schemaLocation=\"TestSchemaLocation\""
" xmlns:xsi=\"TestNamespaceXSI\""
" xmlns:ext=\"TestNamespaceEXT\""
" id=\"testId\""
" type=\"static\""
" availabilityStartTime=\"2015-03-24T1:10:50+08:00\""
" availabilityEndTime=\"2015-03-24T1:10:50.123456-04:30\""
" mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
" minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
" minBufferTime=\"P0Y1M2DT12H10M20.5S\""
" timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
" suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
" maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
" maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\"></MPD>";
gboolean ret;
GstMPDClient *mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
availabilityStartTime = mpdclient->mpd_root_node->availabilityStartTime;
assert_equals_int (gst_date_time_get_year (availabilityStartTime), 2015);
assert_equals_int (gst_date_time_get_month (availabilityStartTime), 3);
assert_equals_int (gst_date_time_get_day (availabilityStartTime), 24);
assert_equals_int (gst_date_time_get_hour (availabilityStartTime), 1);
assert_equals_int (gst_date_time_get_minute (availabilityStartTime), 10);
assert_equals_int (gst_date_time_get_second (availabilityStartTime), 50);
assert_equals_int (gst_date_time_get_microsecond (availabilityStartTime), 0);
assert_equals_float (gst_date_time_get_time_zone_offset
(availabilityStartTime), 8.0);
availabilityEndTime = mpdclient->mpd_root_node->availabilityEndTime;
assert_equals_int (gst_date_time_get_year (availabilityEndTime), 2015);
assert_equals_int (gst_date_time_get_month (availabilityEndTime), 3);
assert_equals_int (gst_date_time_get_day (availabilityEndTime), 24);
assert_equals_int (gst_date_time_get_hour (availabilityEndTime), 1);
assert_equals_int (gst_date_time_get_minute (availabilityEndTime), 10);
assert_equals_int (gst_date_time_get_second (availabilityEndTime), 50);
assert_equals_int (gst_date_time_get_microsecond (availabilityEndTime),
123456);
assert_equals_float (gst_date_time_get_time_zone_offset (availabilityEndTime),
-4.5);
gst_mpd_client_free (mpdclient);
}
GST_END_TEST;
/*
* Test generate xml content.
*
*/
GST_START_TEST (dash_mpdparser_check_mpd_xml_generator)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" schemaLocation=\"TestSchemaLocation\""
" xmlns:xsi=\"TestNamespaceXSI\""
" xmlns:ext=\"TestNamespaceEXT\""
" id=\"testId\""
" type=\"static\""
" availabilityStartTime=\"2015-03-24T1:10:50+08:00\""
" availabilityEndTime=\"2015-03-24T1:10:50.123456-04:30\""
" mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
" minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
" minBufferTime=\"P0Y1M2DT12H10M20.5S\""
" timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
" suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
" maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
" maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\">"
" <BaseURL serviceLocation=\"TestServiceLocation\""
" byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
" <Location>TestLocation</Location>"
" <ProgramInformation lang=\"en\""
" moreInformationURL=\"TestMoreInformationUrl\">"
" <Title>TestTitle</Title>"
" <Source>TestSource</Source>"
" <Copyright>TestCopyright</Copyright>"
" </ProgramInformation>"
" <Metrics metrics=\"TestMetric\"><Range starttime=\"P0Y1M2DT12H10M20.5S\""
" duration=\"P0Y1M2DT12H10M20.1234567S\">"
" </Range></Metrics>"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"1\" bandwidth=\"250000\">"
" <SegmentTemplate duration=\"1\">"
" </SegmentTemplate>"
" </Representation></AdaptationSet></Period>" " </MPD>";
gboolean ret;
gchar *new_xml;
gint new_xml_size;
GstMPDClient *first_mpdclient = NULL;
GstMPDClient *second_mpdclient = NULL;
GstMPDBaseURLNode *first_baseURL, *second_baseURL;
GstMPDLocationNode *first_location, *second_location;
GstMPDProgramInformationNode *first_prog_info, *second_prog_info;
GstMPDMetricsNode *first_metrics, *second_metrics;
GstMPDMetricsRangeNode *first_metrics_range, *second_metrics_range;
first_mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (first_mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
gst_mpd_client_get_xml_content (first_mpdclient, &new_xml, &new_xml_size);
second_mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (second_mpdclient, new_xml, new_xml_size);
assert_equals_int (ret, TRUE);
g_free (new_xml);
/* assert that parameters are equal */
assert_equals_string (first_mpdclient->mpd_root_node->default_namespace,
second_mpdclient->mpd_root_node->default_namespace);
assert_equals_string (first_mpdclient->mpd_root_node->namespace_xsi,
second_mpdclient->mpd_root_node->namespace_xsi);
assert_equals_string (first_mpdclient->mpd_root_node->namespace_ext,
second_mpdclient->mpd_root_node->namespace_ext);
assert_equals_string (first_mpdclient->mpd_root_node->schemaLocation,
second_mpdclient->mpd_root_node->schemaLocation);
assert_equals_string (first_mpdclient->mpd_root_node->id,
second_mpdclient->mpd_root_node->id);
assert_equals_string (first_mpdclient->mpd_root_node->profiles,
second_mpdclient->mpd_root_node->profiles);
assert_equals_uint64 (first_mpdclient->
mpd_root_node->mediaPresentationDuration,
second_mpdclient->mpd_root_node->mediaPresentationDuration);
assert_equals_uint64 (first_mpdclient->mpd_root_node->minimumUpdatePeriod,
second_mpdclient->mpd_root_node->minimumUpdatePeriod);
assert_equals_uint64 (first_mpdclient->mpd_root_node->minBufferTime,
second_mpdclient->mpd_root_node->minBufferTime);
assert_equals_uint64 (first_mpdclient->mpd_root_node->timeShiftBufferDepth,
second_mpdclient->mpd_root_node->timeShiftBufferDepth);
assert_equals_uint64 (first_mpdclient->
mpd_root_node->suggestedPresentationDelay,
second_mpdclient->mpd_root_node->suggestedPresentationDelay);
assert_equals_uint64 (first_mpdclient->mpd_root_node->maxSegmentDuration,
second_mpdclient->mpd_root_node->maxSegmentDuration);
assert_equals_uint64 (first_mpdclient->mpd_root_node->maxSubsegmentDuration,
second_mpdclient->mpd_root_node->maxSubsegmentDuration);
/* baseURLs */
first_baseURL =
(GstMPDBaseURLNode *) first_mpdclient->mpd_root_node->BaseURLs->data;
second_baseURL =
(GstMPDBaseURLNode *) second_mpdclient->mpd_root_node->BaseURLs->data;
assert_equals_string (first_baseURL->baseURL, second_baseURL->baseURL);
assert_equals_string (first_baseURL->serviceLocation,
second_baseURL->serviceLocation);
assert_equals_string (first_baseURL->byteRange, second_baseURL->byteRange);
/* locations */
first_location =
(GstMPDLocationNode *) first_mpdclient->mpd_root_node->Locations->data;
second_location =
(GstMPDLocationNode *) second_mpdclient->mpd_root_node->Locations->data;
assert_equals_string (first_location->location, second_location->location);
/* ProgramInformation */
first_prog_info =
(GstMPDProgramInformationNode *) first_mpdclient->mpd_root_node->
ProgramInfos->data;
second_prog_info =
(GstMPDProgramInformationNode *) second_mpdclient->mpd_root_node->
ProgramInfos->data;
assert_equals_string (first_prog_info->lang, second_prog_info->lang);
assert_equals_string (first_prog_info->moreInformationURL,
second_prog_info->moreInformationURL);
assert_equals_string (first_prog_info->Title, second_prog_info->Title);
assert_equals_string (first_prog_info->Source, second_prog_info->Source);
assert_equals_string (first_prog_info->Copyright,
second_prog_info->Copyright);
/* Metrics */
first_metrics =
(GstMPDMetricsNode *) first_mpdclient->mpd_root_node->Metrics->data;
second_metrics =
(GstMPDMetricsNode *) second_mpdclient->mpd_root_node->Metrics->data;
assert_equals_string (first_metrics->metrics, second_metrics->metrics);
/* Metrics Range */
first_metrics_range =
(GstMPDMetricsRangeNode *) first_metrics->MetricsRanges->data;
second_metrics_range =
(GstMPDMetricsRangeNode *) second_metrics->MetricsRanges->data;
assert_equals_uint64 (first_metrics_range->starttime,
second_metrics_range->starttime);
assert_equals_uint64 (first_metrics_range->duration,
second_metrics_range->duration);
gst_mpd_client_free (first_mpdclient);
gst_mpd_client_free (second_mpdclient);
}
GST_END_TEST;
/*
* Test add mpd content with mpd_client set methods
*
*/
GST_START_TEST (dash_mpdparser_check_mpd_client_set_methods)
{
const gchar *xml =
"<?xml version=\"1.0\"?>"
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\""
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\""
" schemaLocation=\"TestSchemaLocation\""
" xmlns:xsi=\"TestNamespaceXSI\""
" xmlns:ext=\"TestNamespaceEXT\""
" id=\"testId\""
" type=\"static\""
" availabilityStartTime=\"2015-03-24T1:10:50+08:00\""
" availabilityEndTime=\"2015-03-24T1:10:50.123456-04:30\""
" mediaPresentationDuration=\"P0Y1M2DT12H10M20.5S\""
" minimumUpdatePeriod=\"P0Y1M2DT12H10M20.5S\""
" minBufferTime=\"P0Y1M2DT12H10M20.5S\""
" timeShiftBufferDepth=\"P0Y1M2DT12H10M20.5S\""
" suggestedPresentationDelay=\"P0Y1M2DT12H10M20.5S\""
" maxSegmentDuration=\"P0Y1M2DT12H10M20.5S\""
" maxSubsegmentDuration=\"P0Y1M2DT12H10M20.5S\">"
" <BaseURL serviceLocation=\"TestServiceLocation\""
" byteRange=\"TestByteRange\">TestBaseURL</BaseURL>"
" <Location>TestLocation</Location>"
" <ProgramInformation lang=\"en\""
" moreInformationURL=\"TestMoreInformationUrl\">"
" <Title>TestTitle</Title>"
" <Source>TestSource</Source>"
" <Copyright>TestCopyright</Copyright>"
" </ProgramInformation>"
" <Metrics metrics=\"TestMetric\"><Range starttime=\"P0Y1M2DT12H10M20.5S\""
" duration=\"P0Y1M2DT12H10M20.1234567S\">"
" </Range></Metrics>"
" <Period id=\"TestId\" start=\"PT1M\" duration=\"PT40S\""
" bitstreamSwitching=\"true\">"
" <AdaptationSet id=\"9\" contentType=\"video\" mimeType=\"video\">"
" <Representation id=\"audio_1\" "
" bandwidth=\"100\""
" qualityRanking=\"200\""
" width=\"640\""
" height=\"480\""
" codecs=\"avc1\""
" audioSamplingRate=\"44100\""
" mimeType=\"audio/mp4\">"
" <SegmentList duration=\"15\" startNumber=\"11\">"
" <SegmentURL media=\"segment001.ts\"></SegmentURL>"
" <SegmentURL media=\"segment002.ts\"></SegmentURL>"
" </SegmentList>"
" </Representation></AdaptationSet></Period>" " </MPD>";
gboolean ret;
gchar *period_id;
guint adaptation_set_id;
gchar *representation_id;
GstMPDClient *first_mpdclient = NULL;
GstMPDClient *second_mpdclient = NULL;
GstMPDBaseURLNode *first_baseURL, *second_baseURL;
GstMPDPeriodNode *first_period, *second_period;
GstMPDAdaptationSetNode *first_adap_set, *second_adap_set;
GstMPDRepresentationNode *first_rep, *second_rep;
GstMPDSegmentListNode *first_seg_list, *second_seg_list;
GstMPDSegmentURLNode *first_seg_url, *second_seg_url;
first_mpdclient = gst_mpd_client_new ();
ret = gst_mpd_client_parse (first_mpdclient, xml, (gint) strlen (xml));
assert_equals_int (ret, TRUE);
second_mpdclient = gst_mpd_client_new ();
gst_mpd_client_set_root_node (second_mpdclient,
"default-namespace", "urn:mpeg:dash:schema:mpd:2011",
"profiles", "urn:mpeg:dash:profile:isoff-main:2011",
"schema-location", "TestSchemaLocation",
"namespace-xsi", "TestNamespaceXSI",
"namespace-ext", "TestNamespaceEXT", "id", "testId", NULL);
gst_mpd_client_add_baseurl_node (second_mpdclient,
"url", "TestBaseURL",
"service-location", "TestServiceLocation",
"byte-range", "TestByteRange", NULL);
period_id = gst_mpd_client_set_period_node (second_mpdclient, (gchar *) "TestId", "start", (guint64) 60000, // ms
"duration", (guint64) 40000, "bitstream-switching", 1, NULL);
adaptation_set_id =
gst_mpd_client_set_adaptation_set_node (second_mpdclient, period_id, 9,
"content-type", "video", "mime-type", "video", NULL);
representation_id =
gst_mpd_client_set_representation_node (second_mpdclient, period_id,
adaptation_set_id, (gchar *) "audio_1", "bandwidth", 100,
"quality-ranking", 200, "mime-type", "audio/mp4", "width", 640, "height",
480, "codecs", "avc1", "audio-sampling-rate", 44100, NULL);
gst_mpd_client_set_segment_list (second_mpdclient, period_id,
adaptation_set_id, representation_id, "duration", 15, "start-number", 11,
NULL);
gst_mpd_client_add_segment_url (second_mpdclient, period_id,
adaptation_set_id, representation_id, "media", "segment001.ts", NULL);
gst_mpd_client_add_segment_url (second_mpdclient, period_id,
adaptation_set_id, representation_id, "media", "segment002.ts", NULL);
/* assert that parameters are equal */
assert_equals_string (first_mpdclient->mpd_root_node->default_namespace,
second_mpdclient->mpd_root_node->default_namespace);
assert_equals_string (first_mpdclient->mpd_root_node->namespace_xsi,
second_mpdclient->mpd_root_node->namespace_xsi);
assert_equals_string (first_mpdclient->mpd_root_node->namespace_ext,
second_mpdclient->mpd_root_node->namespace_ext);
assert_equals_string (first_mpdclient->mpd_root_node->schemaLocation,
second_mpdclient->mpd_root_node->schemaLocation);
assert_equals_string (first_mpdclient->mpd_root_node->id,
second_mpdclient->mpd_root_node->id);
assert_equals_string (first_mpdclient->mpd_root_node->profiles,
second_mpdclient->mpd_root_node->profiles);
/* baseURLs */
first_baseURL =
(GstMPDBaseURLNode *) first_mpdclient->mpd_root_node->BaseURLs->data;
second_baseURL =
(GstMPDBaseURLNode *) second_mpdclient->mpd_root_node->BaseURLs->data;
assert_equals_string (first_baseURL->baseURL, second_baseURL->baseURL);
assert_equals_string (first_baseURL->serviceLocation,
second_baseURL->serviceLocation);
assert_equals_string (first_baseURL->byteRange, second_baseURL->byteRange);
/* Period */
first_period =
(GstMPDPeriodNode *) first_mpdclient->mpd_root_node->Periods->data;
second_period =
(GstMPDPeriodNode *) second_mpdclient->mpd_root_node->Periods->data;
assert_equals_string (first_period->id, second_period->id);
assert_equals_int64 (first_period->start, second_period->start);
assert_equals_int64 (first_period->duration, second_period->duration);
assert_equals_int (first_period->bitstreamSwitching,
second_period->bitstreamSwitching);
/* Adaptation set */
first_adap_set =
(GstMPDAdaptationSetNode *) first_period->AdaptationSets->data;
second_adap_set =
(GstMPDAdaptationSetNode *) second_period->AdaptationSets->data;
assert_equals_int (first_adap_set->id, second_adap_set->id);
assert_equals_string (first_adap_set->contentType,
second_adap_set->contentType);
assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE
(first_adap_set)->mimeType,
GST_MPD_REPRESENTATION_BASE_NODE (second_adap_set)->mimeType);
/* Representation */
first_rep =
(GstMPDRepresentationNode *) first_adap_set->Representations->data;
second_rep =
(GstMPDRepresentationNode *) second_adap_set->Representations->data;
assert_equals_string (first_rep->id, second_rep->id);
assert_equals_int (first_rep->bandwidth, second_rep->bandwidth);
assert_equals_int (first_rep->qualityRanking, second_rep->qualityRanking);
assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->mimeType,
GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->mimeType);
assert_equals_int (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->width,
GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->width);
assert_equals_int (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->height,
GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->height);
assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE (first_rep)->codecs,
GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->codecs);
assert_equals_string (GST_MPD_REPRESENTATION_BASE_NODE
(first_rep)->audioSamplingRate,
GST_MPD_REPRESENTATION_BASE_NODE (second_rep)->audioSamplingRate);
/*SegmentList */
first_seg_list = (GstMPDSegmentListNode *) first_rep->SegmentList;
second_seg_list = (GstMPDSegmentListNode *) second_rep->SegmentList;
assert_equals_int (GST_MPD_MULT_SEGMENT_BASE_NODE (first_seg_list)->duration,
GST_MPD_MULT_SEGMENT_BASE_NODE (second_seg_list)->duration);
assert_equals_int (GST_MPD_MULT_SEGMENT_BASE_NODE
(first_seg_list)->startNumber,
GST_MPD_MULT_SEGMENT_BASE_NODE (second_seg_list)->startNumber);
first_seg_url = (GstMPDSegmentURLNode *) first_seg_list->SegmentURL->data;
second_seg_url = (GstMPDSegmentURLNode *) second_seg_list->SegmentURL->data;
assert_equals_string (first_seg_url->media, second_seg_url->media);
gst_mpd_client_free (first_mpdclient);
gst_mpd_client_free (second_mpdclient);
}
GST_END_TEST;
/*
* create a test suite containing all dash testcases
*/
static Suite *
dash_suite (void)
{
Suite *s = suite_create ("dash");
TCase *tc_simpleMPD = tcase_create ("simpleMPD");
TCase *tc_complexMPD = tcase_create ("complexMPD");
TCase *tc_negativeTests = tcase_create ("negativeTests");
TCase *tc_stringTests = tcase_create ("stringTests");
TCase *tc_duration = tcase_create ("duration");
GST_DEBUG_CATEGORY_INIT (gst_dash_demux_debug, "gst_dash_demux_debug", 0,
"mpeg dash tests");
/* test parsing the simplest possible mpd */
tcase_add_test (tc_simpleMPD, dash_mpdparser_validsimplempd);
/* test parsing the simplest possible mpd */
tcase_add_test (tc_simpleMPD, dash_mpdparser_check_mpd_xml_generator);
/* test mpd client set methods */
tcase_add_test (tc_simpleMPD, dash_mpdparser_check_mpd_client_set_methods);
/* tests parsing attributes from each element type */
tcase_add_test (tc_simpleMPD, dash_mpdparser_mpd);
tcase_add_test (tc_simpleMPD, dash_mpdparser_datetime_with_tz_offset);
tcase_add_test (tc_simpleMPD, dash_mpdparser_programInformation);
tcase_add_test (tc_simpleMPD, dash_mpdparser_baseURL);
tcase_add_test (tc_simpleMPD, dash_mpdparser_location);
tcase_add_test (tc_simpleMPD, dash_mpdparser_metrics);
tcase_add_test (tc_simpleMPD, dash_mpdparser_metrics_range);
tcase_add_test (tc_simpleMPD, dash_mpdparser_metrics_reporting);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_baseURL);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentBase);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentBase_initialization);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentBase_representationIndex);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentList);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentList_multipleSegmentBaseType);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentBaseType);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentList_multipleSegmentBaseType_segmentTimeline_s);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentList_multipleSegmentBaseType_bitstreamSwitching);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentList_segmentURL);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_segmentTemplate);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplateWithPresentationTimeOffset);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentBaseType);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_segmentTimeline_s);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_segmentTemplate_multipleSegmentBaseType_bitstreamSwitching);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representationBase);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representationBase_framePacking);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_adapt_repr_segmentTemplate_inherit);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representationBase_audioChannelConfiguration);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representationBase_contentProtection);
tcase_add_test (tc_simpleMPD, dash_mpdparser_contentProtection_no_value);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_contentProtection_no_value_no_encoding);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representationBase_contentProtection_with_content);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representationBase_contentProtection_xml_namespaces);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_accessibility);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_role);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_rating);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_viewpoint);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_contentComponent);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_contentComponent_accessibility);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_contentComponent_role);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_contentComponent_rating);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_contentComponent_viewpoint);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_adaptationSet_baseURL);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_segmentBase);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_segmentBase_initialization);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_segmentBase_representationIndex);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_segmentList);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_segmentTemplate);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_segmentTemplate_inherit);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_representationBase);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_baseURL);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_subRepresentation);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_subRepresentation_representationBase);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_segmentBase);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_segmentList);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_segmentTemplate);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_segmentTemplate_inherit);
tcase_add_test (tc_simpleMPD,
dash_mpdparser_period_adaptationSet_representation_segmentBase_inherit);
tcase_add_test (tc_simpleMPD, dash_mpdparser_period_subset);
dashdemux: add support for UTCTiming elements for clock drift compensation Unless the DASH client can compensate for the difference between its clock and the clock used by the server, the client might request fragments that either not yet on the server or fragments that have already been expired from the server. This is an issue because these requests can propagate all the way back to the origin ISO/IEC 23009-1:2014/Amd 1 [PDAM1] defines a new UTCTiming element to allow a DASH client to track the clock used by the server generating the DASH stream. Multiple UTCTiming elements might be present, to indicate support for multiple methods of UTC time gathering. Each element can contain a white space separated list of URLs that can be contacted to discover the UTC time from the server's perspective. This commit provides parsing of UTCTiming elements, unit tests of this parsing and a function to poll a time server. This function supports the following methods: urn:mpeg:dash:utc:ntp:2014 urn:mpeg:dash:utc:http-xsdate:2014 urn:mpeg:dash:utc:http-iso:2014 urn:mpeg:dash:utc:http-ntp:2014 The manifest update task is used to poll the clock time server, to save having to create a new thread. When choosing the starting fragment number and when waiting for a fragment to become available, the difference between the server's idea of UTC and the client's idea of UTC is taken into account. For example, if the server's time is behind the client's idea of UTC, we wait for longer before requesting a fragment [PDAM1]: http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=66068 dashdemux: support NTP time servers in UTCTiming elements Use the gst_ntp_clock to support the use of an NTP server. https://bugzilla.gnome.org/show_bug.cgi?id=752413
2015-07-15 10:56:13 +00:00
tcase_add_test (tc_simpleMPD, dash_mpdparser_utctiming);
tcase_add_test (tc_simpleMPD, dash_mpdparser_utctiming_invalid_value);
/* tests checking other possible values for attributes */
tcase_add_test (tc_simpleMPD, dash_mpdparser_type_dynamic);
tcase_add_test (tc_simpleMPD, dash_mpdparser_template_parsing);
tcase_add_test (tc_simpleMPD, dash_mpdparser_isoff_ondemand_profile);
tcase_add_test (tc_simpleMPD, dash_mpdparser_GstDateTime);
tcase_add_test (tc_simpleMPD, dash_mpdparser_bitstreamSwitching_inheritance);
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)
*/
tcase_add_test (tc_complexMPD, dash_mpdparser_setup_media_presentation);
tcase_add_test (tc_complexMPD, dash_mpdparser_setup_streaming);
tcase_add_test (tc_complexMPD, dash_mpdparser_period_selection);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_period_at_time);
tcase_add_test (tc_complexMPD, dash_mpdparser_adaptationSet_handling);
tcase_add_test (tc_complexMPD, dash_mpdparser_representation_selection);
tcase_add_test (tc_complexMPD, dash_mpdparser_multipleSegmentURL);
tcase_add_test (tc_complexMPD, dash_mpdparser_activeStream_selection);
tcase_add_test (tc_complexMPD, dash_mpdparser_activeStream_parameters);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_audio_languages);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL1);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL2);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL3);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL4);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL5);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL6);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL7);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL8);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_baseURL_with_query);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_mediaPresentationDuration);
tcase_add_test (tc_complexMPD, dash_mpdparser_get_streamPresentationOffset);
tcase_add_test (tc_complexMPD, dash_mpdparser_segments);
tcase_add_test (tc_complexMPD, dash_mpdparser_headers);
tcase_add_test (tc_complexMPD, dash_mpdparser_fragments);
tcase_add_test (tc_complexMPD, dash_mpdparser_inherited_segmentBase);
tcase_add_test (tc_complexMPD, dash_mpdparser_inherited_segmentURL);
tcase_add_test (tc_complexMPD, dash_mpdparser_segment_list);
tcase_add_test (tc_complexMPD, dash_mpdparser_segment_template);
tcase_add_test (tc_complexMPD, dash_mpdparser_segment_timeline);
tcase_add_test (tc_complexMPD, dash_mpdparser_multiple_inherited_segmentURL);
/* tests checking the parsing of missing/incomplete attributes of xml */
tcase_add_test (tc_negativeTests, dash_mpdparser_missing_xml);
tcase_add_test (tc_negativeTests, dash_mpdparser_missing_mpd);
tcase_add_test (tc_negativeTests, dash_mpdparser_no_end_tag);
tcase_add_test (tc_negativeTests, dash_mpdparser_no_profiles);
tcase_add_test (tc_negativeTests, dash_mpdparser_no_default_namespace);
tcase_add_test (tc_negativeTests,
dash_mpdparser_wrong_period_duration_inferred_from_next_period);
tcase_add_test (tc_negativeTests,
dash_mpdparser_wrong_period_duration_inferred_from_next_mediaPresentationDuration);
tcase_add_test (tc_negativeTests, dash_mpdparser_negative_period_duration);
tcase_add_test (tc_negativeTests,
dash_mpdparser_read_unsigned_from_negative_values);
tcase_add_test (tc_negativeTests,
dash_mpdparser_negative_mediaPresentationDuration);
tcase_add_test (tc_negativeTests,
dash_mpdparser_unmatched_segmentTimeline_segmentURL);
tcase_add_test (tc_stringTests, dash_mpdparser_whitespace_strings);
tcase_add_test (tc_stringTests, dash_mpdparser_rfc1738_strings);
tcase_add_test (tc_duration, dash_mpdparser_duration);
tcase_add_test (tc_duration, dash_mpdparser_maximum_segment_duration);
suite_add_tcase (s, tc_simpleMPD);
suite_add_tcase (s, tc_complexMPD);
suite_add_tcase (s, tc_negativeTests);
suite_add_tcase (s, tc_stringTests);
suite_add_tcase (s, tc_duration);
return s;
}
GST_CHECK_MAIN (dash);