2013-05-08 14:13:32 +00:00
/*
2012-10-08 08:24:29 +00:00
* DASH MPD parsing library
2013-05-08 14:13:32 +00:00
*
2012-10-08 08:24:29 +00:00
* gstmpdparser . c
2013-05-08 14:13:32 +00:00
*
2012-10-08 08:24:29 +00:00
* Copyright ( C ) 2012 STMicroelectronics
2013-05-08 14:13:32 +00:00
*
2012-10-08 08:24:29 +00:00
* Authors :
* Gianluca Gennari < gennarone @ gmail . com >
2013-05-08 14:13:32 +00:00
*
* 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
2012-10-08 08:24:29 +00:00
* version 2.1 of the License , or ( at your option ) any later version .
2013-05-08 14:13:32 +00:00
*
* 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
2012-10-08 08:24:29 +00:00
* License along with this library ( COPYING ) ; if not , write to the
2013-05-08 14:13:32 +00:00
* Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*/
# include <string.h>
2019-05-20 16:48:23 +00:00
2013-05-08 14:13:32 +00:00
# include "gstmpdparser.h"
2013-06-25 21:34:13 +00:00
# include "gstdash_debug.h"
# define GST_CAT_DEFAULT gst_dash_demux_debug
2013-05-08 14:13:32 +00:00
/* XML node parsing */
static void gst_mpdparser_parse_baseURL_node ( GList * * list , xmlNode * a_node ) ;
2019-05-24 14:24:00 +00:00
static void gst_mpdparser_parse_descriptor_type ( GList * * list ,
2012-12-20 08:04:28 +00:00
xmlNode * a_node ) ;
static void gst_mpdparser_parse_content_component_node ( GList * * list ,
xmlNode * a_node ) ;
2013-05-08 14:13:32 +00:00
static void gst_mpdparser_parse_location_node ( GList * * list , xmlNode * a_node ) ;
2012-12-20 08:04:28 +00:00
static void gst_mpdparser_parse_subrepresentation_node ( GList * * list ,
xmlNode * a_node ) ;
static void gst_mpdparser_parse_segment_url_node ( GList * * list ,
xmlNode * a_node ) ;
2019-12-04 16:25:24 +00:00
static void gst_mpdparser_parse_url_type_node ( GstMPDURLTypeNode * * pointer ,
2012-12-20 08:04:28 +00:00
xmlNode * a_node ) ;
2019-12-04 16:25:24 +00:00
static void gst_mpdparser_parse_seg_base_type_ext ( GstMPDSegmentBaseNode * *
pointer , xmlNode * a_node , GstMPDSegmentBaseNode * parent ) ;
2013-07-05 02:42:23 +00:00
static void gst_mpdparser_parse_s_node ( GQueue * queue , xmlNode * a_node ) ;
2019-05-24 14:24:00 +00:00
static void gst_mpdparser_parse_segment_timeline_node ( GstMPDSegmentTimelineNode
* * pointer , xmlNode * a_node ) ;
2015-10-28 15:34:29 +00:00
static gboolean
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_mult_seg_base_node ( GstMPDMultSegmentBaseNode *
pointer , xmlNode * a_node , GstMPDMultSegmentBaseNode * parent ) ;
2019-05-24 14:24:00 +00:00
static gboolean gst_mpdparser_parse_segment_list_node ( GstMPDSegmentListNode * *
pointer , xmlNode * a_node , GstMPDSegmentListNode * parent ) ;
2012-12-20 08:04:28 +00:00
static void
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_representation_base ( GstMPDRepresentationBaseNode *
2012-12-20 08:04:28 +00:00
pointer , xmlNode * a_node ) ;
2015-10-28 15:34:29 +00:00
static gboolean gst_mpdparser_parse_representation_node ( GList * * list ,
2019-05-24 14:24:00 +00:00
xmlNode * a_node , GstMPDAdaptationSetNode * parent ,
GstMPDPeriodNode * period_node ) ;
2015-10-28 15:34:29 +00:00
static gboolean gst_mpdparser_parse_adaptation_set_node ( GList * * list ,
2019-05-24 14:24:00 +00:00
xmlNode * a_node , GstMPDPeriodNode * parent ) ;
2013-05-08 14:13:32 +00:00
static void gst_mpdparser_parse_subset_node ( GList * * list , xmlNode * a_node ) ;
2015-10-28 15:34:29 +00:00
static gboolean
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_segment_template_node ( GstMPDSegmentTemplateNode * * pointer ,
xmlNode * a_node , GstMPDSegmentTemplateNode * parent ) ;
2015-10-28 15:34:29 +00:00
static gboolean gst_mpdparser_parse_period_node ( GList * * list ,
xmlNode * a_node ) ;
2012-12-20 08:04:28 +00:00
static void gst_mpdparser_parse_program_info_node ( GList * * list ,
xmlNode * a_node ) ;
static void gst_mpdparser_parse_metrics_range_node ( GList * * list ,
xmlNode * a_node ) ;
2013-05-08 14:13:32 +00:00
static void gst_mpdparser_parse_metrics_node ( GList * * list , xmlNode * a_node ) ;
2019-05-24 14:24:00 +00:00
static gboolean gst_mpdparser_parse_root_node ( GstMPDRootNode * * pointer ,
2012-12-20 08:04:28 +00:00
xmlNode * a_node ) ;
2015-07-15 10:56:13 +00:00
static void gst_mpdparser_parse_utctiming_node ( GList * * list ,
xmlNode * a_node ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
/*
Duration Data Type
2015-07-10 15:56:29 +00:00
2019-05-20 16:48:23 +00:00
The duration data type is used to specify a time interval .
2015-09-29 15:17:03 +00:00
2019-05-20 16:48:23 +00:00
The time interval is specified in the following form " -PnYnMnDTnHnMnS " where :
2016-04-22 20:04:57 +00:00
2019-05-20 16:48:23 +00:00
* - indicates the negative sign ( optional )
* P indicates the period ( required )
* nY indicates the number of years
* nM indicates the number of months
* nD indicates the number of days
* T indicates the start of a time section ( required if you are going to specify hours , minutes , or seconds )
* nH indicates the number of hours
* nM indicates the number of minutes
* nS indicates the number of seconds
*/
2015-09-29 15:17:03 +00:00
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
static void
gst_mpdparser_parse_baseURL_node ( GList * * list , xmlNode * a_node )
2015-09-08 14:14:13 +00:00
{
2019-05-24 14:24:00 +00:00
GstMPDBaseURLNode * new_base_url ;
2015-09-08 14:14:13 +00:00
2019-05-24 14:24:00 +00:00
new_base_url = gst_mpd_baseurl_node_new ( ) ;
2019-05-20 16:48:23 +00:00
* list = g_list_append ( * list , new_base_url ) ;
2015-09-08 14:14:13 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " content of BaseURL node: " ) ;
gst_xml_helper_get_node_content ( a_node , & new_base_url - > baseURL ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of BaseURL node: " ) ;
gst_xml_helper_get_prop_string ( a_node , " serviceLocation " ,
& new_base_url - > serviceLocation ) ;
gst_xml_helper_get_prop_string ( a_node , " byteRange " ,
& new_base_url - > byteRange ) ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
static void
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( GList * * list , xmlNode * a_node )
2013-02-19 22:35:34 +00:00
{
2019-12-04 16:25:24 +00:00
GstMPDDescriptorTypeNode * new_descriptor ;
2013-02-19 22:35:34 +00:00
2019-12-04 16:25:24 +00:00
new_descriptor =
gst_mpd_descriptor_type_node_new ( ( const gchar * ) a_node - > name ) ;
2019-05-20 16:48:23 +00:00
* list = g_list_append ( * list , new_descriptor ) ;
2013-02-19 22:35:34 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of %s node: " , a_node - > name ) ;
gst_xml_helper_get_prop_string_stripped ( a_node , " schemeIdUri " ,
& new_descriptor - > schemeIdUri ) ;
if ( ! gst_xml_helper_get_prop_string ( a_node , " value " , & new_descriptor - > value ) ) {
/* if no value attribute, use XML string representation of the node */
gst_xml_helper_get_node_as_string ( a_node , & new_descriptor - > value ) ;
2013-05-08 14:13:32 +00:00
}
}
2019-05-20 16:48:23 +00:00
static void
gst_mpdparser_parse_content_component_node ( GList * * list , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
2019-05-20 16:48:23 +00:00
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDContentComponentNode * new_content_component ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_content_component = gst_mpd_content_component_node_new ( ) ;
2019-05-20 16:48:23 +00:00
* list = g_list_append ( * list , new_content_component ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of ContentComponent node: " ) ;
gst_xml_helper_get_prop_unsigned_integer ( a_node , " id " , 0 ,
& new_content_component - > id ) ;
gst_xml_helper_get_prop_string ( a_node , " lang " , & new_content_component - > lang ) ;
gst_xml_helper_get_prop_string ( a_node , " contentType " ,
& new_content_component - > contentType ) ;
gst_xml_helper_get_prop_ratio ( a_node , " par " , & new_content_component - > par ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Accessibility " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type
2019-05-20 16:48:23 +00:00
( & new_content_component - > Accessibility , cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Role " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( & new_content_component - > Role ,
2019-05-20 16:48:23 +00:00
cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Rating " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type
2019-05-20 16:48:23 +00:00
( & new_content_component - > Rating , cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Viewpoint " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type
2019-05-20 16:48:23 +00:00
( & new_content_component - > Viewpoint , cur_node ) ;
}
2013-05-08 14:13:32 +00:00
}
}
}
2019-05-20 16:48:23 +00:00
static void
gst_mpdparser_parse_location_node ( GList * * list , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
2019-05-20 16:48:23 +00:00
gchar * location = NULL ;
2019-12-04 16:25:24 +00:00
GstMPDLocationNode * locationNode ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " content of Location node: " ) ;
2019-12-04 16:25:24 +00:00
if ( gst_xml_helper_get_node_content ( a_node , & location ) ) {
locationNode = gst_mpd_location_node_new ( ) ;
locationNode - > location = location ;
* list = g_list_append ( * list , locationNode ) ;
}
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
static void
gst_mpdparser_parse_subrepresentation_node ( GList * * list , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
2019-05-24 14:24:00 +00:00
GstMPDSubRepresentationNode * new_subrep ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_subrep = gst_mpd_sub_representation_node_new ( ) ;
2019-05-20 16:48:23 +00:00
* list = g_list_append ( * list , new_subrep ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of SubRepresentation node: " ) ;
gst_xml_helper_get_prop_unsigned_integer ( a_node , " level " , 0 ,
& new_subrep - > level ) ;
gst_xml_helper_get_prop_uint_vector_type ( a_node , " dependencyLevel " ,
2019-12-04 16:25:24 +00:00
& new_subrep - > dependencyLevel , & new_subrep - > dependencyLevel_size ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " bandwidth " , 0 ,
& new_subrep - > bandwidth ) ;
gst_xml_helper_get_prop_string_vector_type ( a_node ,
" contentComponent " , & new_subrep - > contentComponent ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
/* RepresentationBase extension */
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_representation_base ( GST_MPD_REPRESENTATION_BASE_NODE
( new_subrep ) , a_node ) ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
static void
gst_mpdparser_parse_segment_url_node ( GList * * list , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
2019-05-24 14:24:00 +00:00
GstMPDSegmentURLNode * new_segment_url ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_segment_url = gst_mpd_segment_url_node_new ( ) ;
2019-05-20 16:48:23 +00:00
* list = g_list_append ( * list , new_segment_url ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of SegmentURL node: " ) ;
gst_xml_helper_get_prop_string ( a_node , " media " , & new_segment_url - > media ) ;
gst_xml_helper_get_prop_range ( a_node , " mediaRange " ,
& new_segment_url - > mediaRange ) ;
gst_xml_helper_get_prop_string ( a_node , " index " , & new_segment_url - > index ) ;
gst_xml_helper_get_prop_range ( a_node , " indexRange " ,
& new_segment_url - > indexRange ) ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
static void
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_url_type_node ( GstMPDURLTypeNode * * pointer ,
xmlNode * a_node )
2019-05-20 16:48:23 +00:00
{
2019-12-04 16:25:24 +00:00
GstMPDURLTypeNode * new_url_type ;
2013-05-08 14:13:32 +00:00
2019-12-04 16:25:24 +00:00
gst_mpd_url_type_node_free ( * pointer ) ;
* pointer = new_url_type =
gst_mpd_url_type_node_new ( ( const gchar * ) a_node - > name ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of URLType node: " ) ;
gst_xml_helper_get_prop_string ( a_node , " sourceURL " ,
& new_url_type - > sourceURL ) ;
gst_xml_helper_get_prop_range ( a_node , " range " , & new_url_type - > range ) ;
}
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
static void
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_seg_base_type_ext ( GstMPDSegmentBaseNode * * pointer ,
xmlNode * a_node , GstMPDSegmentBaseNode * parent )
2013-05-08 14:13:32 +00:00
{
2019-05-20 16:48:23 +00:00
xmlNode * cur_node ;
2019-12-04 16:25:24 +00:00
GstMPDSegmentBaseNode * seg_base_type ;
2019-05-20 16:48:23 +00:00
guint intval ;
guint64 int64val ;
gboolean boolval ;
GstXMLRange * rangeval ;
2017-12-14 07:18:38 +00:00
2019-12-04 16:25:24 +00:00
gst_mpd_segment_base_node_free ( * pointer ) ;
* pointer = seg_base_type = gst_mpd_segment_base_node_new ( ) ;
2017-12-14 07:18:38 +00:00
2019-05-20 16:48:23 +00:00
/* Initialize values that have defaults */
seg_base_type - > indexRangeExact = FALSE ;
seg_base_type - > timescale = 1 ;
2017-12-14 07:18:38 +00:00
2019-05-20 16:48:23 +00:00
/* Inherit attribute values from parent */
if ( parent ) {
seg_base_type - > timescale = parent - > timescale ;
seg_base_type - > presentationTimeOffset = parent - > presentationTimeOffset ;
seg_base_type - > indexRange = gst_xml_helper_clone_range ( parent - > indexRange ) ;
seg_base_type - > indexRangeExact = parent - > indexRangeExact ;
seg_base_type - > Initialization =
2019-12-04 16:25:24 +00:00
gst_mpd_url_type_node_clone ( parent - > Initialization ) ;
2019-05-20 16:48:23 +00:00
seg_base_type - > RepresentationIndex =
2019-12-04 16:25:24 +00:00
gst_mpd_url_type_node_clone ( parent - > RepresentationIndex ) ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
/* We must retrieve each value first to see if it exists. If it does not
* exist , we do not want to overwrite an inherited value */
GST_LOG ( " attributes of SegmentBaseType extension: " ) ;
if ( gst_xml_helper_get_prop_unsigned_integer ( a_node , " timescale " , 1 ,
& intval ) ) {
seg_base_type - > timescale = intval ;
2015-11-02 10:25:38 +00:00
}
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_unsigned_integer_64 ( a_node ,
" presentationTimeOffset " , 0 , & int64val ) ) {
seg_base_type - > presentationTimeOffset = int64val ;
2015-11-02 10:25:38 +00:00
}
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_range ( a_node , " indexRange " , & rangeval ) ) {
if ( seg_base_type - > indexRange ) {
g_slice_free ( GstXMLRange , seg_base_type - > indexRange ) ;
}
seg_base_type - > indexRange = rangeval ;
2015-11-02 10:25:38 +00:00
}
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_boolean ( a_node , " indexRangeExact " ,
FALSE , & boolval ) ) {
seg_base_type - > indexRangeExact = boolval ;
2015-11-02 10:25:38 +00:00
}
2019-05-20 16:48:23 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Initialization " ) = = 0 | |
xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Initialisation " ) = = 0 ) {
/* parse will free the previous pointer to create a new one */
gst_mpdparser_parse_url_type_node ( & seg_base_type - > Initialization ,
cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name ,
( xmlChar * ) " RepresentationIndex " ) = = 0 ) {
/* parse will free the previous pointer to create a new one */
gst_mpdparser_parse_url_type_node ( & seg_base_type - > RepresentationIndex ,
cur_node ) ;
2015-11-02 10:25:38 +00:00
}
2019-05-20 16:48:23 +00:00
}
2015-11-02 10:25:38 +00:00
}
}
2015-09-29 08:32:02 +00:00
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
static void
gst_mpdparser_parse_s_node ( GQueue * queue , xmlNode * a_node )
2015-02-06 13:22:14 +00:00
{
2019-05-24 14:24:00 +00:00
GstMPDSNode * new_s_node ;
2015-08-19 10:29:43 +00:00
2019-05-24 14:24:00 +00:00
new_s_node = gst_mpd_s_node_new ( ) ;
2019-05-20 16:48:23 +00:00
g_queue_push_tail ( queue , new_s_node ) ;
GST_LOG ( " attributes of S node: " ) ;
gst_xml_helper_get_prop_unsigned_integer_64 ( a_node , " t " , 0 , & new_s_node - > t ) ;
gst_xml_helper_get_prop_unsigned_integer_64 ( a_node , " d " , 0 , & new_s_node - > d ) ;
gst_xml_helper_get_prop_signed_integer ( a_node , " r " , 0 , & new_s_node - > r ) ;
2015-02-06 13:22:14 +00:00
}
2013-05-08 14:13:32 +00:00
static void
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_segment_timeline_node ( GstMPDSegmentTimelineNode * * pointer ,
2019-05-20 16:48:23 +00:00
xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
2019-05-20 16:48:23 +00:00
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDSegmentTimelineNode * new_seg_timeline ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
gst_mpd_segment_timeline_node_free ( * pointer ) ;
* pointer = new_seg_timeline = gst_mpd_segment_timeline_node_new ( ) ;
2019-05-20 16:48:23 +00:00
if ( new_seg_timeline = = NULL ) {
GST_WARNING ( " Allocation of SegmentTimeline node failed! " ) ;
return ;
}
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " S " ) = = 0 ) {
gst_mpdparser_parse_s_node ( & new_seg_timeline - > S , cur_node ) ;
}
}
}
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
static gboolean
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_mult_seg_base_node ( GstMPDMultSegmentBaseNode *
mult_seg_base_node , xmlNode * a_node , GstMPDMultSegmentBaseNode * parent )
2013-05-08 14:13:32 +00:00
{
2019-05-20 16:48:23 +00:00
xmlNode * cur_node ;
2019-12-04 16:25:24 +00:00
2019-05-20 16:48:23 +00:00
guint intval ;
gboolean has_timeline = FALSE , has_duration = FALSE ;
2013-05-08 14:13:32 +00:00
2019-12-04 16:25:24 +00:00
mult_seg_base_node - > duration = 0 ;
mult_seg_base_node - > startNumber = 1 ;
2019-05-20 16:48:23 +00:00
/* Inherit attribute values from parent */
if ( parent ) {
2019-12-04 16:25:24 +00:00
mult_seg_base_node - > duration = parent - > duration ;
mult_seg_base_node - > startNumber = parent - > startNumber ;
mult_seg_base_node - > SegmentTimeline =
2019-05-24 14:24:00 +00:00
gst_mpd_segment_timeline_node_clone ( parent - > SegmentTimeline ) ;
2019-12-04 16:25:24 +00:00
mult_seg_base_node - > BitstreamSwitching =
gst_mpd_url_type_node_clone ( parent - > BitstreamSwitching ) ;
2015-02-06 13:22:14 +00:00
}
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of MultipleSegmentBaseType extension: " ) ;
if ( gst_xml_helper_get_prop_unsigned_integer ( a_node , " duration " , 0 , & intval ) ) {
2019-12-04 16:25:24 +00:00
mult_seg_base_node - > duration = intval ;
2019-05-20 16:48:23 +00:00
}
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
/* duration might be specified from parent */
2019-12-04 16:25:24 +00:00
if ( mult_seg_base_node - > duration )
2019-05-20 16:48:23 +00:00
has_duration = TRUE ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_unsigned_integer ( a_node , " startNumber " , 1 ,
& intval ) ) {
2019-12-04 16:25:24 +00:00
mult_seg_base_node - > startNumber = intval ;
2019-05-20 16:48:23 +00:00
}
GST_LOG ( " extension of MultipleSegmentBaseType extension: " ) ;
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_seg_base_type_ext ( & mult_seg_base_node - > SegmentBase ,
a_node , ( parent ? parent - > SegmentBase : NULL ) ) ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
2019-05-20 16:48:23 +00:00
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentTimeline " ) = = 0 ) {
/* parse frees the segmenttimeline if any */
gst_mpdparser_parse_segment_timeline_node
2019-12-04 16:25:24 +00:00
( & mult_seg_base_node - > SegmentTimeline , cur_node ) ;
2019-05-20 16:48:23 +00:00
} else if ( xmlStrcmp ( cur_node - > name ,
( xmlChar * ) " BitstreamSwitching " ) = = 0 ) {
/* parse frees the old url before setting the new one */
gst_mpdparser_parse_url_type_node
2019-12-04 16:25:24 +00:00
( & mult_seg_base_node - > BitstreamSwitching , cur_node ) ;
2013-05-08 14:13:32 +00:00
}
}
}
2019-12-04 16:25:24 +00:00
has_timeline = mult_seg_base_node - > SegmentTimeline ! = NULL ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
/* Checking duration and timeline only at Representation's child level */
if ( xmlStrcmp ( a_node - > parent - > name , ( xmlChar * ) " Representation " ) = = 0
& & ! has_duration & & ! has_timeline ) {
GST_ERROR ( " segment has neither duration nor timeline " ) ;
}
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
return TRUE ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
static gboolean
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_segment_list_node ( GstMPDSegmentListNode * * pointer ,
xmlNode * a_node , GstMPDSegmentListNode * parent )
2013-05-08 14:13:32 +00:00
{
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDSegmentListNode * new_segment_list ;
2019-05-20 16:48:23 +00:00
gchar * actuate ;
gboolean segment_urls_inherited_from_parent = FALSE ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
gst_mpd_segment_list_node_free ( * pointer ) ;
new_segment_list = gst_mpd_segment_list_node_new ( ) ;
2013-06-21 23:09:30 +00:00
/* Inherit attribute values from parent */
if ( parent ) {
2019-05-20 16:48:23 +00:00
GList * list ;
2019-05-24 14:24:00 +00:00
GstMPDSegmentURLNode * seg_url ;
2019-05-20 16:48:23 +00:00
for ( list = g_list_first ( parent - > SegmentURL ) ; list ;
list = g_list_next ( list ) ) {
2019-05-24 14:24:00 +00:00
seg_url = ( GstMPDSegmentURLNode * ) list - > data ;
2019-05-20 16:48:23 +00:00
new_segment_list - > SegmentURL =
g_list_append ( new_segment_list - > SegmentURL ,
2019-05-24 14:24:00 +00:00
gst_mpd_segment_url_node_clone ( seg_url ) ) ;
2019-05-20 16:48:23 +00:00
segment_urls_inherited_from_parent = TRUE ;
2013-06-21 23:09:30 +00:00
}
}
2019-05-20 16:48:23 +00:00
2019-05-24 14:24:00 +00:00
new_segment_list - > actuate = GST_MPD_XLINK_ACTUATE_ON_REQUEST ;
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_ns_prop_string ( a_node ,
" http://www.w3.org/1999/xlink " , " href " , & new_segment_list - > xlink_href )
& & gst_xml_helper_get_ns_prop_string ( a_node ,
" http://www.w3.org/1999/xlink " , " actuate " , & actuate ) ) {
2019-12-04 16:25:24 +00:00
if ( strcmp ( actuate , GST_MPD_XLINK_ACTUATE_ON_LOAD_STR ) = = 0 )
2019-05-24 14:24:00 +00:00
new_segment_list - > actuate = GST_MPD_XLINK_ACTUATE_ON_LOAD ;
2019-05-20 16:48:23 +00:00
xmlFree ( actuate ) ;
2013-06-21 23:09:30 +00:00
}
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
GST_LOG ( " extension of SegmentList node: " ) ;
2019-12-04 16:25:24 +00:00
if ( ! gst_mpdparser_parse_mult_seg_base_node
( GST_MPD_MULT_SEGMENT_BASE_NODE ( new_segment_list ) , a_node ,
( parent ? GST_MPD_MULT_SEGMENT_BASE_NODE ( parent ) : NULL ) ) )
2019-05-20 16:48:23 +00:00
goto error ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
2019-05-20 16:48:23 +00:00
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentURL " ) = = 0 ) {
if ( segment_urls_inherited_from_parent ) {
/*
* SegmentBase , SegmentTemplate and SegmentList shall inherit
* attributes and elements from the same element on a higher level .
* If the same attribute or element is present on both levels ,
* the one on the lower level shall take precedence over the one
* on the higher level .
*/
/* Clear the list of inherited segment URLs */
g_list_free_full ( new_segment_list - > SegmentURL ,
2019-05-24 14:24:00 +00:00
( GDestroyNotify ) gst_mpd_segment_url_node_free ) ;
2019-05-20 16:48:23 +00:00
new_segment_list - > SegmentURL = NULL ;
/* mark the fact that we cleared the list, so that it is not tried again */
segment_urls_inherited_from_parent = FALSE ;
}
gst_mpdparser_parse_segment_url_node ( & new_segment_list - > SegmentURL ,
2012-12-20 08:04:28 +00:00
cur_node ) ;
2013-05-08 14:13:32 +00:00
}
}
}
2013-06-21 23:09:30 +00:00
2019-05-20 16:48:23 +00:00
* pointer = new_segment_list ;
return TRUE ;
2013-06-21 23:09:30 +00:00
2019-05-20 16:48:23 +00:00
error :
2019-05-24 14:24:00 +00:00
gst_mpd_segment_list_node_free ( new_segment_list ) ;
2019-05-20 16:48:23 +00:00
return FALSE ;
2013-06-21 23:09:30 +00:00
}
2013-05-08 14:13:32 +00:00
static void
2019-05-20 16:48:23 +00:00
gst_mpdparser_parse_content_protection_node ( GList * * list , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
2019-05-20 16:48:23 +00:00
gchar * value = NULL ;
if ( gst_xml_helper_get_prop_string ( a_node , " value " , & value ) ) {
if ( ! g_strcmp0 ( value , " MSPR 2.0 " ) ) {
xmlNode * cur_node ;
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " pro " ) = = 0 ) {
2019-12-04 16:25:24 +00:00
GstMPDDescriptorTypeNode * new_descriptor ;
new_descriptor = gst_mpd_descriptor_type_node_new ( ( const gchar * )
cur_node - > name ) ;
2019-05-20 16:48:23 +00:00
* list = g_list_append ( * list , new_descriptor ) ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string_stripped ( a_node , " schemeIdUri " ,
& new_descriptor - > schemeIdUri ) ;
2013-06-21 23:09:30 +00:00
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_node_content ( cur_node , & new_descriptor - > value ) ;
goto beach ;
}
2013-06-21 23:09:30 +00:00
}
}
} else {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( list , a_node ) ;
2013-06-21 23:09:30 +00:00
}
2019-05-20 16:48:23 +00:00
} else {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( list , a_node ) ;
2013-06-21 23:09:30 +00:00
}
2019-05-20 16:48:23 +00:00
beach :
if ( value )
g_free ( value ) ;
2013-06-21 23:09:30 +00:00
}
2013-05-08 14:13:32 +00:00
static void
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_representation_base ( GstMPDRepresentationBaseNode *
representation_base , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
xmlNode * cur_node ;
2019-05-20 16:48:23 +00:00
GST_LOG ( " attributes of RepresentationBaseType extension: " ) ;
gst_xml_helper_get_prop_string ( a_node , " profiles " ,
& representation_base - > profiles ) ;
gst_xml_helper_get_prop_unsigned_integer ( a_node , " width " , 0 ,
& representation_base - > width ) ;
gst_xml_helper_get_prop_unsigned_integer ( a_node , " height " , 0 ,
& representation_base - > height ) ;
gst_xml_helper_get_prop_ratio ( a_node , " sar " , & representation_base - > sar ) ;
gst_xml_helper_get_prop_framerate ( a_node , " frameRate " ,
& representation_base - > frameRate ) ;
gst_xml_helper_get_prop_framerate ( a_node , " minFrameRate " ,
& representation_base - > minFrameRate ) ;
gst_xml_helper_get_prop_framerate ( a_node , " maxFrameRate " ,
& representation_base - > maxFrameRate ) ;
gst_xml_helper_get_prop_string ( a_node , " audioSamplingRate " ,
& representation_base - > audioSamplingRate ) ;
gst_xml_helper_get_prop_string ( a_node , " mimeType " ,
& representation_base - > mimeType ) ;
gst_xml_helper_get_prop_string ( a_node , " segmentProfiles " ,
& representation_base - > segmentProfiles ) ;
gst_xml_helper_get_prop_string ( a_node , " codecs " ,
& representation_base - > codecs ) ;
gst_xml_helper_get_prop_double ( a_node , " maximumSAPPeriod " ,
& representation_base - > maximumSAPPeriod ) ;
gst_mpd_helper_get_SAP_type ( a_node , " startWithSAP " ,
& representation_base - > startWithSAP ) ;
gst_xml_helper_get_prop_double ( a_node , " maxPlayoutRate " ,
& representation_base - > maxPlayoutRate ) ;
gst_xml_helper_get_prop_boolean ( a_node , " codingDependency " ,
FALSE , & representation_base - > codingDependency ) ;
gst_xml_helper_get_prop_string ( a_node , " scanType " ,
& representation_base - > scanType ) ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
2019-05-20 16:48:23 +00:00
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " FramePacking " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type
2019-05-20 16:48:23 +00:00
( & representation_base - > FramePacking , cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name ,
( xmlChar * ) " AudioChannelConfiguration " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type
2019-05-20 16:48:23 +00:00
( & representation_base - > AudioChannelConfiguration , cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name ,
( xmlChar * ) " ContentProtection " ) = = 0 ) {
gst_mpdparser_parse_content_protection_node
( & representation_base - > ContentProtection , cur_node ) ;
2013-05-08 14:13:32 +00:00
}
}
}
}
2015-10-28 15:34:29 +00:00
static gboolean
2019-05-20 16:48:23 +00:00
gst_mpdparser_parse_representation_node ( GList * * list , xmlNode * a_node ,
2019-05-24 14:24:00 +00:00
GstMPDAdaptationSetNode * parent , GstMPDPeriodNode * period_node )
2013-05-08 14:13:32 +00:00
{
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDRepresentationNode * new_representation ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_representation = gst_mpd_representation_node_new ( ) ;
2013-05-08 14:13:32 +00:00
GST_LOG ( " attributes of Representation node: " ) ;
2019-05-20 16:48:23 +00:00
if ( ! gst_xml_helper_get_prop_string_no_whitespace ( a_node , " id " ,
2017-03-27 00:56:32 +00:00
& new_representation - > id ) ) {
GST_ERROR ( " Cannot parse Representation id, invalid manifest " ) ;
2017-04-12 08:54:23 +00:00
goto error ;
2017-03-27 00:56:32 +00:00
}
2019-05-20 16:48:23 +00:00
if ( ! gst_xml_helper_get_prop_unsigned_integer ( a_node , " bandwidth " , 0 ,
2017-03-27 00:56:32 +00:00
& new_representation - > bandwidth ) ) {
GST_ERROR ( " Cannot parse Representation bandwidth, invalid manifest " ) ;
2017-04-12 08:54:23 +00:00
goto error ;
2017-03-27 00:56:32 +00:00
}
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " qualityRanking " , 0 ,
2013-06-21 21:51:46 +00:00
& new_representation - > qualityRanking ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string_vector_type ( a_node , " dependencyId " ,
2013-06-21 21:51:46 +00:00
& new_representation - > dependencyId ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string_vector_type ( a_node ,
2013-06-21 21:51:46 +00:00
" mediaStreamStructureId " , & new_representation - > mediaStreamStructureId ) ;
2013-05-08 14:13:32 +00:00
/* RepresentationBase extension */
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_representation_base
( GST_MPD_REPRESENTATION_BASE_NODE ( new_representation ) , a_node ) ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentBase " ) = = 0 ) {
2012-12-20 08:04:28 +00:00
gst_mpdparser_parse_seg_base_type_ext ( & new_representation - > SegmentBase ,
2017-03-27 01:06:30 +00:00
cur_node , parent - > SegmentBase ?
parent - > SegmentBase : period_node - > SegmentBase ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentTemplate " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_segment_template_node
2013-06-21 23:09:30 +00:00
( & new_representation - > SegmentTemplate , cur_node ,
2017-03-27 01:06:30 +00:00
parent - > SegmentTemplate ?
parent - > SegmentTemplate : period_node - > SegmentTemplate ) )
2015-10-28 15:34:29 +00:00
goto error ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentList " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_segment_list_node
2016-07-16 18:15:21 +00:00
( & new_representation - > SegmentList , cur_node ,
2019-05-24 14:24:00 +00:00
parent - > SegmentList ? parent - > SegmentList : period_node - >
SegmentList ) )
2015-10-28 15:34:29 +00:00
goto error ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " BaseURL " ) = = 0 ) {
2012-12-20 08:04:28 +00:00
gst_mpdparser_parse_baseURL_node ( & new_representation - > BaseURLs ,
cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name ,
( xmlChar * ) " SubRepresentation " ) = = 0 ) {
2013-01-25 12:36:35 +00:00
gst_mpdparser_parse_subrepresentation_node
( & new_representation - > SubRepresentations , cur_node ) ;
2013-05-08 14:13:32 +00:00
}
}
}
2015-10-28 15:34:29 +00:00
/* some sanity checking */
* list = g_list_append ( * list , new_representation ) ;
return TRUE ;
error :
2019-05-24 14:24:00 +00:00
gst_mpd_representation_node_free ( new_representation ) ;
2015-10-28 15:34:29 +00:00
return FALSE ;
2013-05-08 14:13:32 +00:00
}
2015-10-28 15:34:29 +00:00
static gboolean
2013-06-21 23:09:30 +00:00
gst_mpdparser_parse_adaptation_set_node ( GList * * list , xmlNode * a_node ,
2019-05-24 14:24:00 +00:00
GstMPDPeriodNode * parent )
2013-05-08 14:13:32 +00:00
{
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDAdaptationSetNode * new_adap_set ;
2015-07-10 15:56:29 +00:00
gchar * actuate ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_adap_set = gst_mpd_adaptation_set_node_new ( ) ;
2013-05-08 14:13:32 +00:00
GST_LOG ( " attributes of AdaptationSet node: " ) ;
2015-07-10 15:56:29 +00:00
2019-05-24 14:24:00 +00:00
new_adap_set - > actuate = GST_MPD_XLINK_ACTUATE_ON_REQUEST ;
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_ns_prop_string ( a_node ,
2015-07-10 15:56:29 +00:00
" http://www.w3.org/1999/xlink " , " href " , & new_adap_set - > xlink_href )
2019-05-20 16:48:23 +00:00
& & gst_xml_helper_get_ns_prop_string ( a_node ,
2015-07-10 15:56:29 +00:00
" http://www.w3.org/1999/xlink " , " actuate " , & actuate ) ) {
if ( strcmp ( actuate , " onLoad " ) = = 0 )
2019-05-24 14:24:00 +00:00
new_adap_set - > actuate = GST_MPD_XLINK_ACTUATE_ON_LOAD ;
2015-07-10 15:56:29 +00:00
xmlFree ( actuate ) ;
}
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " id " , 0 , & new_adap_set - > id ) ;
gst_xml_helper_get_prop_unsigned_integer ( a_node , " group " , 0 ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > group ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string ( a_node , " lang " , & new_adap_set - > lang ) ;
gst_xml_helper_get_prop_string ( a_node , " contentType " ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > contentType ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_ratio ( a_node , " par " , & new_adap_set - > par ) ;
gst_xml_helper_get_prop_unsigned_integer ( a_node , " minBandwidth " , 0 ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > minBandwidth ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " maxBandwidth " , 0 ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > maxBandwidth ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " minWidth " , 0 ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > minWidth ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " maxWidth " , 0 ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > maxWidth ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " minHeight " , 0 ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > minHeight ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_unsigned_integer ( a_node , " maxHeight " , 0 ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > maxHeight ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_cond_uint ( a_node , " segmentAlignment " ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > segmentAlignment ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_boolean ( a_node , " bitstreamSwitching " ,
2015-10-30 15:55:19 +00:00
parent - > bitstreamSwitching , & new_adap_set - > bitstreamSwitching ) ;
if ( parent - > bitstreamSwitching & & ! new_adap_set - > bitstreamSwitching ) {
/* according to the standard, if the Period's bitstreamSwitching attribute
* is true , the AdaptationSet should not have the bitstreamSwitching
* attribute set to false .
* We should return a parsing error , but we are generous and ignore the
* standard violation .
*/
new_adap_set - > bitstreamSwitching = parent - > bitstreamSwitching ;
}
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_cond_uint ( a_node , " subsegmentAlignment " ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > subsegmentAlignment ) ;
2019-05-20 16:48:23 +00:00
gst_mpd_helper_get_SAP_type ( a_node , " subsegmentStartsWithSAP " ,
2013-06-21 21:51:46 +00:00
& new_adap_set - > subsegmentStartsWithSAP ) ;
2013-05-08 14:13:32 +00:00
/* RepresentationBase extension */
2019-12-04 16:25:24 +00:00
gst_mpdparser_parse_representation_base
( GST_MPD_REPRESENTATION_BASE_NODE ( new_adap_set ) , a_node ) ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
2012-10-08 09:47:45 +00:00
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Accessibility " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( & new_adap_set - > Accessibility ,
2012-12-20 08:04:28 +00:00
cur_node ) ;
2012-10-08 09:47:45 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Role " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( & new_adap_set - > Role , cur_node ) ;
2012-10-08 09:47:45 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Rating " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( & new_adap_set - > Rating , cur_node ) ;
2012-10-08 09:47:45 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Viewpoint " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_descriptor_type ( & new_adap_set - > Viewpoint ,
2012-12-20 08:04:28 +00:00
cur_node ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " BaseURL " ) = = 0 ) {
gst_mpdparser_parse_baseURL_node ( & new_adap_set - > BaseURLs , cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentBase " ) = = 0 ) {
2012-12-20 08:04:28 +00:00
gst_mpdparser_parse_seg_base_type_ext ( & new_adap_set - > SegmentBase ,
2013-06-21 23:09:30 +00:00
cur_node , parent - > SegmentBase ) ;
2012-10-08 09:16:09 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentList " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_segment_list_node ( & new_adap_set - > SegmentList ,
cur_node , parent - > SegmentList ) )
goto error ;
2012-12-20 08:04:28 +00:00
} else if ( xmlStrcmp ( cur_node - > name ,
( xmlChar * ) " ContentComponent " ) = = 0 ) {
2013-01-25 12:36:35 +00:00
gst_mpdparser_parse_content_component_node
( & new_adap_set - > ContentComponents , cur_node ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentTemplate " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_segment_template_node
( & new_adap_set - > SegmentTemplate , cur_node , parent - > SegmentTemplate ) )
goto error ;
2013-06-21 23:09:30 +00:00
}
}
}
/* We must parse Representation after everything else in the AdaptationSet
* has been parsed because certain Representation child elements can inherit
* attributes specified by the same element in the AdaptationSet
*/
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Representation " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_representation_node
2016-07-16 18:15:21 +00:00
( & new_adap_set - > Representations , cur_node , new_adap_set , parent ) )
2015-10-28 15:34:29 +00:00
goto error ;
2013-05-08 14:13:32 +00:00
}
}
}
2015-10-28 15:34:29 +00:00
* list = g_list_append ( * list , new_adap_set ) ;
return TRUE ;
error :
2019-05-24 14:24:00 +00:00
gst_mpd_adaptation_set_node_free ( new_adap_set ) ;
2015-10-28 15:34:29 +00:00
return FALSE ;
2013-05-08 14:13:32 +00:00
}
static void
gst_mpdparser_parse_subset_node ( GList * * list , xmlNode * a_node )
{
2019-05-24 14:24:00 +00:00
GstMPDSubsetNode * new_subset ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_subset = gst_mpd_subset_node_new ( ) ;
2013-05-08 14:13:32 +00:00
* list = g_list_append ( * list , new_subset ) ;
GST_LOG ( " attributes of Subset node: " ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_uint_vector_type ( a_node , " contains " ,
2019-12-04 16:25:24 +00:00
& new_subset - > contains , & new_subset - > contains_size ) ;
2013-05-08 14:13:32 +00:00
}
2015-10-28 15:34:29 +00:00
static gboolean
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_segment_template_node ( GstMPDSegmentTemplateNode * * pointer ,
xmlNode * a_node , GstMPDSegmentTemplateNode * parent )
2013-05-08 14:13:32 +00:00
{
2019-05-24 14:24:00 +00:00
GstMPDSegmentTemplateNode * new_segment_template ;
2013-06-21 23:09:30 +00:00
gchar * strval ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
gst_mpd_segment_template_node_free ( * pointer ) ;
new_segment_template = gst_mpd_segment_template_node_new ( ) ;
2013-05-08 14:13:32 +00:00
GST_LOG ( " extension of SegmentTemplate node: " ) ;
2019-12-04 16:25:24 +00:00
if ( ! gst_mpdparser_parse_mult_seg_base_node
( GST_MPD_MULT_SEGMENT_BASE_NODE ( new_segment_template ) , a_node ,
( parent ? GST_MPD_MULT_SEGMENT_BASE_NODE ( parent ) : NULL ) ) )
2015-10-28 15:34:29 +00:00
goto error ;
2013-05-08 14:13:32 +00:00
2015-08-01 18:52:28 +00:00
/* Inherit attribute values from parent when the value isn't found */
2013-05-08 14:13:32 +00:00
GST_LOG ( " attributes of SegmentTemplate node: " ) ;
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_string ( a_node , " media " , & strval ) ) {
2013-06-21 23:09:30 +00:00
new_segment_template - > media = strval ;
2015-08-01 18:52:28 +00:00
} else if ( parent ) {
new_segment_template - > media = xmlMemStrdup ( parent - > media ) ;
2013-06-21 23:09:30 +00:00
}
2015-08-01 18:52:28 +00:00
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_string ( a_node , " index " , & strval ) ) {
2013-06-21 23:09:30 +00:00
new_segment_template - > index = strval ;
2015-08-01 18:52:28 +00:00
} else if ( parent ) {
new_segment_template - > index = xmlMemStrdup ( parent - > index ) ;
2013-06-21 23:09:30 +00:00
}
2015-08-01 18:52:28 +00:00
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_string ( a_node , " initialization " , & strval ) ) {
2013-06-21 23:09:30 +00:00
new_segment_template - > initialization = strval ;
2015-08-01 18:52:28 +00:00
} else if ( parent ) {
new_segment_template - > initialization =
xmlMemStrdup ( parent - > initialization ) ;
2013-06-21 23:09:30 +00:00
}
2015-08-01 18:52:28 +00:00
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_string ( a_node , " bitstreamSwitching " , & strval ) ) {
2013-06-21 23:09:30 +00:00
new_segment_template - > bitstreamSwitching = strval ;
2015-08-01 18:52:28 +00:00
} else if ( parent ) {
new_segment_template - > bitstreamSwitching =
xmlMemStrdup ( parent - > bitstreamSwitching ) ;
2013-06-21 23:09:30 +00:00
}
2015-10-28 15:34:29 +00:00
* pointer = new_segment_template ;
return TRUE ;
error :
2019-05-24 14:24:00 +00:00
gst_mpd_segment_template_node_free ( new_segment_template ) ;
2015-10-28 15:34:29 +00:00
return FALSE ;
2013-05-08 14:13:32 +00:00
}
2015-10-28 15:34:29 +00:00
static gboolean
2013-05-08 14:13:32 +00:00
gst_mpdparser_parse_period_node ( GList * * list , xmlNode * a_node )
{
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDPeriodNode * new_period ;
2015-07-10 15:56:29 +00:00
gchar * actuate ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_period = gst_mpd_period_node_new ( ) ;
2013-05-08 14:13:32 +00:00
GST_LOG ( " attributes of Period node: " ) ;
2015-07-10 15:56:29 +00:00
2019-05-24 14:24:00 +00:00
new_period - > actuate = GST_MPD_XLINK_ACTUATE_ON_REQUEST ;
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_ns_prop_string ( a_node ,
2015-07-10 15:56:29 +00:00
" http://www.w3.org/1999/xlink " , " href " , & new_period - > xlink_href )
2019-05-20 16:48:23 +00:00
& & gst_xml_helper_get_ns_prop_string ( a_node ,
2015-07-10 15:56:29 +00:00
" http://www.w3.org/1999/xlink " , " actuate " , & actuate ) ) {
if ( strcmp ( actuate , " onLoad " ) = = 0 )
2019-05-24 14:24:00 +00:00
new_period - > actuate = GST_MPD_XLINK_ACTUATE_ON_LOAD ;
2015-07-10 15:56:29 +00:00
xmlFree ( actuate ) ;
}
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string ( a_node , " id " , & new_period - > id ) ;
gst_xml_helper_get_prop_duration ( a_node , " start " , GST_MPD_DURATION_NONE ,
2015-10-29 11:38:35 +00:00
& new_period - > start ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " duration " ,
2015-10-29 11:38:35 +00:00
GST_MPD_DURATION_NONE , & new_period - > duration ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_boolean ( a_node , " bitstreamSwitching " , FALSE ,
2015-10-29 11:38:35 +00:00
& new_period - > bitstreamSwitching ) ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
2013-06-21 23:09:30 +00:00
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentBase " ) = = 0 ) {
2012-12-20 08:04:28 +00:00
gst_mpdparser_parse_seg_base_type_ext ( & new_period - > SegmentBase ,
2013-06-21 23:09:30 +00:00
cur_node , NULL ) ;
2012-12-20 08:04:28 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentList " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_segment_list_node ( & new_period - > SegmentList ,
cur_node , NULL ) )
goto error ;
2012-12-20 08:04:28 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " SegmentTemplate " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_segment_template_node
( & new_period - > SegmentTemplate , cur_node , NULL ) )
goto error ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Subset " ) = = 0 ) {
gst_mpdparser_parse_subset_node ( & new_period - > Subsets , cur_node ) ;
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " BaseURL " ) = = 0 ) {
gst_mpdparser_parse_baseURL_node ( & new_period - > BaseURLs , cur_node ) ;
}
}
}
2013-06-21 23:09:30 +00:00
/* We must parse AdaptationSet after everything else in the Period has been
* parsed because certain AdaptationSet child elements can inherit attributes
* specified by the same element in the Period
*/
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " AdaptationSet " ) = = 0 ) {
2015-10-28 15:34:29 +00:00
if ( ! gst_mpdparser_parse_adaptation_set_node
( & new_period - > AdaptationSets , cur_node , new_period ) )
goto error ;
2013-06-21 23:09:30 +00:00
}
}
}
2015-10-28 15:34:29 +00:00
* list = g_list_append ( * list , new_period ) ;
return TRUE ;
error :
2019-05-24 14:24:00 +00:00
gst_mpd_period_node_free ( new_period ) ;
2015-10-28 15:34:29 +00:00
return FALSE ;
2013-05-08 14:13:32 +00:00
}
static void
2012-10-08 09:30:40 +00:00
gst_mpdparser_parse_program_info_node ( GList * * list , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDProgramInformationNode * new_prog_info ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_prog_info = gst_mpd_program_information_node_new ( ) ;
2012-10-08 09:30:40 +00:00
* list = g_list_append ( * list , new_prog_info ) ;
2013-05-08 14:13:32 +00:00
GST_LOG ( " attributes of ProgramInformation node: " ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string ( a_node , " lang " , & new_prog_info - > lang ) ;
gst_xml_helper_get_prop_string ( a_node , " moreInformationURL " ,
2013-06-21 21:51:46 +00:00
& new_prog_info - > moreInformationURL ) ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
GST_LOG ( " children of ProgramInformation node: " ) ;
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Title " ) = = 0 ) {
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_node_content ( cur_node , & new_prog_info - > Title ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Source " ) = = 0 ) {
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_node_content ( cur_node , & new_prog_info - > Source ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Copyright " ) = = 0 ) {
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_node_content ( cur_node , & new_prog_info - > Copyright ) ;
2013-05-08 14:13:32 +00:00
}
}
}
}
static void
gst_mpdparser_parse_metrics_range_node ( GList * * list , xmlNode * a_node )
{
2019-05-24 14:24:00 +00:00
GstMPDMetricsRangeNode * new_metrics_range ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_metrics_range = gst_mpd_metrics_range_node_new ( ) ;
2013-05-08 14:13:32 +00:00
* list = g_list_append ( * list , new_metrics_range ) ;
GST_LOG ( " attributes of Metrics Range node: " ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " starttime " ,
2015-10-29 11:38:35 +00:00
GST_MPD_DURATION_NONE , & new_metrics_range - > starttime ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " duration " ,
2015-10-29 11:38:35 +00:00
GST_MPD_DURATION_NONE , & new_metrics_range - > duration ) ;
2013-05-08 14:13:32 +00:00
}
static void
gst_mpdparser_parse_metrics_node ( GList * * list , xmlNode * a_node )
{
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDMetricsNode * new_metrics ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
new_metrics = gst_mpd_metrics_node_new ( ) ;
2013-05-08 14:13:32 +00:00
* list = g_list_append ( * list , new_metrics ) ;
GST_LOG ( " attributes of Metrics node: " ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string ( a_node , " metrics " , & new_metrics - > metrics ) ;
2013-05-08 14:13:32 +00:00
/* explore children nodes */
GST_LOG ( " children of Metrics node: " ) ;
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Range " ) = = 0 ) {
2012-12-20 08:04:28 +00:00
gst_mpdparser_parse_metrics_range_node ( & new_metrics - > MetricsRanges ,
cur_node ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Reporting " ) = = 0 ) {
/* No reporting scheme is specified in this part of ISO/IEC 23009.
* It is expected that external specifications may define formats
* and delivery for the reporting data . */
GST_LOG ( " - Reporting node found (unknown structure) " ) ;
}
}
}
}
2015-07-15 10:56:13 +00:00
/* The UTCTiming element is defined in
* ISO / IEC 23009 - 1 : 2014 / PDAM 1 " Information technology — Dynamic adaptive streaming over HTTP (DASH) — Part 1: Media presentation description and segment formats / Amendment 1: High Profile and Availability Time Synchronization "
*/
static void
gst_mpdparser_parse_utctiming_node ( GList * * list , xmlNode * a_node )
{
2019-05-24 14:24:00 +00:00
GstMPDUTCTimingNode * new_timing ;
2015-07-15 10:56:13 +00:00
gchar * method = NULL ;
gchar * value = NULL ;
2019-05-24 14:24:00 +00:00
new_timing = gst_mpd_utctiming_node_new ( ) ;
2015-07-15 10:56:13 +00:00
GST_LOG ( " attributes of UTCTiming node: " ) ;
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_string ( a_node , " schemeIdUri " , & method ) ) {
2019-12-04 16:25:24 +00:00
new_timing - > method = gst_mpd_utctiming_get_method ( method ) ;
2015-07-15 10:56:13 +00:00
xmlFree ( method ) ;
}
2015-08-16 10:52:09 +00:00
2019-05-20 16:48:23 +00:00
if ( gst_xml_helper_get_prop_string ( a_node , " value " , & value ) ) {
2015-07-15 10:56:13 +00:00
int max_tokens = 0 ;
if ( GST_MPD_UTCTIMING_TYPE_DIRECT = = new_timing - > method ) {
/* The GST_MPD_UTCTIMING_TYPE_DIRECT method is a special case
* that is not a space separated list .
*/
max_tokens = 1 ;
}
new_timing - > urls = g_strsplit ( value , " " , max_tokens ) ;
xmlFree ( value ) ;
2015-12-16 13:59:18 +00:00
}
/* append to list only if both method and urls were set */
if ( new_timing - > method ! = 0 & & new_timing - > urls ! = NULL & &
g_strv_length ( new_timing - > urls ) ! = 0 ) {
2015-07-15 10:56:13 +00:00
* list = g_list_append ( * list , new_timing ) ;
2015-08-16 10:52:09 +00:00
} else {
2019-05-24 14:24:00 +00:00
gst_mpd_utctiming_node_free ( new_timing ) ;
2015-07-15 10:56:13 +00:00
}
}
2015-10-28 15:34:29 +00:00
static gboolean
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_root_node ( GstMPDRootNode * * pointer , xmlNode * a_node )
2013-05-08 14:13:32 +00:00
{
xmlNode * cur_node ;
2019-05-24 14:24:00 +00:00
GstMPDRootNode * new_mpd_root ;
2013-05-08 14:13:32 +00:00
2019-05-24 14:24:00 +00:00
gst_mpd_root_node_free ( * pointer ) ;
2015-10-28 15:34:29 +00:00
* pointer = NULL ;
2019-05-24 14:24:00 +00:00
new_mpd_root = gst_mpd_root_node_new ( ) ;
2013-05-08 14:13:32 +00:00
GST_LOG ( " namespaces of root MPD node: " ) ;
2019-05-24 14:24:00 +00:00
new_mpd_root - > default_namespace =
gst_xml_helper_get_node_namespace ( a_node , NULL ) ;
new_mpd_root - > namespace_xsi =
gst_xml_helper_get_node_namespace ( a_node , " xsi " ) ;
new_mpd_root - > namespace_ext =
gst_xml_helper_get_node_namespace ( a_node , " ext " ) ;
2013-05-08 14:13:32 +00:00
GST_LOG ( " attributes of root MPD node: " ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_string ( a_node , " schemaLocation " ,
2019-05-24 14:24:00 +00:00
& new_mpd_root - > schemaLocation ) ;
gst_xml_helper_get_prop_string ( a_node , " id " , & new_mpd_root - > id ) ;
gst_xml_helper_get_prop_string ( a_node , " profiles " , & new_mpd_root - > profiles ) ;
gst_mpd_helper_get_mpd_type ( a_node , " type " , & new_mpd_root - > type ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_dateTime ( a_node , " availabilityStartTime " ,
2019-05-24 14:24:00 +00:00
& new_mpd_root - > availabilityStartTime ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_dateTime ( a_node , " availabilityEndTime " ,
2019-05-24 14:24:00 +00:00
& new_mpd_root - > availabilityEndTime ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " mediaPresentationDuration " ,
2019-05-24 14:24:00 +00:00
GST_MPD_DURATION_NONE , & new_mpd_root - > mediaPresentationDuration ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " minimumUpdatePeriod " ,
2019-05-24 14:24:00 +00:00
GST_MPD_DURATION_NONE , & new_mpd_root - > minimumUpdatePeriod ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " minBufferTime " ,
2019-05-24 14:24:00 +00:00
GST_MPD_DURATION_NONE , & new_mpd_root - > minBufferTime ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " timeShiftBufferDepth " ,
2019-05-24 14:24:00 +00:00
GST_MPD_DURATION_NONE , & new_mpd_root - > timeShiftBufferDepth ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " suggestedPresentationDelay " ,
2019-05-24 14:24:00 +00:00
GST_MPD_DURATION_NONE , & new_mpd_root - > suggestedPresentationDelay ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " maxSegmentDuration " ,
2019-05-24 14:24:00 +00:00
GST_MPD_DURATION_NONE , & new_mpd_root - > maxSegmentDuration ) ;
2019-05-20 16:48:23 +00:00
gst_xml_helper_get_prop_duration ( a_node , " maxSubsegmentDuration " ,
2019-05-24 14:24:00 +00:00
GST_MPD_DURATION_NONE , & new_mpd_root - > maxSubsegmentDuration ) ;
2013-05-08 14:13:32 +00:00
/* explore children Period nodes */
for ( cur_node = a_node - > children ; cur_node ; cur_node = cur_node - > next ) {
if ( cur_node - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Period " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
if ( ! gst_mpdparser_parse_period_node ( & new_mpd_root - > Periods , cur_node ) )
2015-10-28 15:34:29 +00:00
goto error ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name ,
( xmlChar * ) " ProgramInformation " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_program_info_node ( & new_mpd_root - > ProgramInfos ,
cur_node ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " BaseURL " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_baseURL_node ( & new_mpd_root - > BaseURLs , cur_node ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Location " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_location_node ( & new_mpd_root - > Locations , cur_node ) ;
2013-05-08 14:13:32 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " Metrics " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_metrics_node ( & new_mpd_root - > Metrics , cur_node ) ;
2015-07-15 10:56:13 +00:00
} else if ( xmlStrcmp ( cur_node - > name , ( xmlChar * ) " UTCTiming " ) = = 0 ) {
2019-05-24 14:24:00 +00:00
gst_mpdparser_parse_utctiming_node ( & new_mpd_root - > UTCTimings ,
cur_node ) ;
2013-05-08 14:13:32 +00:00
}
}
}
2015-10-28 15:34:29 +00:00
2019-05-24 14:24:00 +00:00
* pointer = new_mpd_root ;
2015-10-28 15:34:29 +00:00
return TRUE ;
error :
2019-05-24 14:24:00 +00:00
gst_mpd_root_node_free ( new_mpd_root ) ;
2015-10-28 15:34:29 +00:00
return FALSE ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
/* internal memory management functions */
2015-05-12 16:41:19 +00:00
2019-05-20 16:48:23 +00:00
/* ISO/IEC 23009-1:2004 5.3.9.4.4 */
static gboolean
validate_format ( const gchar * format )
2014-08-26 19:45:46 +00:00
{
2019-05-20 16:48:23 +00:00
const gchar * p = format ;
2015-05-20 11:08:38 +00:00
2019-05-20 16:48:23 +00:00
/* Check if it starts with % */
if ( ! p | | p [ 0 ] ! = ' % ' )
return FALSE ;
p + + ;
2015-05-11 15:30:03 +00:00
2019-05-20 16:48:23 +00:00
/* the spec mandates a format like %0[width]d */
/* Following the %, we must have a 0 */
if ( p [ 0 ] ! = ' 0 ' )
return FALSE ;
2014-08-26 19:45:46 +00:00
2019-05-20 16:48:23 +00:00
/* Following the % must be a number starting with 0
*/
while ( g_ascii_isdigit ( * p ) )
p + + ;
2015-05-11 15:30:03 +00:00
2019-05-20 16:48:23 +00:00
/* After any 0 and alphanumeric values, there must be a d.
*/
if ( p [ 0 ] ! = ' d ' )
return FALSE ;
p + + ;
2014-08-26 19:45:46 +00:00
2019-05-20 16:48:23 +00:00
/* And then potentially more characters without any
* further % , even if the spec does not mention this
*/
p = strchr ( p , ' % ' ) ;
if ( p )
return FALSE ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
return TRUE ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
static gchar *
promote_format_to_uint64 ( const gchar * format )
2013-07-01 16:19:15 +00:00
{
2019-05-20 16:48:23 +00:00
const gchar * p = format ;
gchar * promoted_format ;
2013-07-01 16:19:15 +00:00
2019-05-20 16:48:23 +00:00
/* Must be called with a validated format! */
g_return_val_if_fail ( validate_format ( format ) , NULL ) ;
2013-07-01 16:19:15 +00:00
2019-05-20 16:48:23 +00:00
/* it starts with % */
p + + ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
/* Following the % must be a 0, or any of d, x or u.
* x and u are not part of the spec , but don ' t hurt us
*/
if ( p [ 0 ] = = ' 0 ' ) {
p + + ;
2012-10-24 14:30:01 +00:00
2019-05-20 16:48:23 +00:00
while ( g_ascii_isdigit ( * p ) )
p + + ;
}
2013-07-05 02:42:23 +00:00
2019-05-20 16:48:23 +00:00
/* After any 0 and alphanumeric values, there must be a d.
* Otherwise validation would have failed
*/
g_assert ( p [ 0 ] = = ' d ' ) ;
2013-07-05 16:22:17 +00:00
2019-05-20 16:48:23 +00:00
promoted_format =
g_strdup_printf ( " %.*s " G_GINT64_MODIFIER " %s " , ( gint ) ( p - format ) ,
format , p ) ;
2015-06-05 12:10:43 +00:00
2019-05-20 16:48:23 +00:00
return promoted_format ;
}
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
static gboolean
gst_mpdparser_validate_rfc1738_url ( const char * s )
{
while ( * s ) {
if ( ! strchr
( " ;:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),%/ " ,
* s ) )
return FALSE ;
if ( * s = = ' % ' ) {
/* g_ascii_isdigit returns FALSE for NUL, and || is a short circuiting
operator , so this is safe for strings ending before two hex digits */
if ( ! g_ascii_isxdigit ( s [ 1 ] ) | | ! g_ascii_isxdigit ( s [ 2 ] ) )
return FALSE ;
s + = 2 ;
2015-06-26 12:09:54 +00:00
}
2019-05-20 16:48:23 +00:00
s + + ;
2013-07-05 16:22:17 +00:00
}
2019-05-20 16:48:23 +00:00
return TRUE ;
2013-05-08 14:13:32 +00:00
}
2019-05-24 14:24:00 +00:00
void
gst_mpdparser_media_fragment_info_clear ( GstMediaFragmentInfo * fragment )
2019-05-20 16:48:23 +00:00
{
g_free ( fragment - > uri ) ;
g_free ( fragment - > index_uri ) ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
/* API */
2013-02-22 19:40:36 +00:00
gboolean
2019-05-24 14:24:00 +00:00
gst_mpdparser_get_mpd_root_node ( GstMPDRootNode * * mpd_root_node ,
const gchar * data , gint size )
2013-02-22 19:40:36 +00:00
{
gboolean ret = FALSE ;
2019-05-20 16:48:23 +00:00
if ( data ) {
xmlDocPtr doc ;
xmlNode * root_element = NULL ;
2013-02-22 19:40:36 +00:00
2019-05-20 16:48:23 +00:00
GST_DEBUG ( " MPD file fully buffered, start parsing... " ) ;
/* parse the complete MPD file into a tree (using the libxml2 default parser API) */
/* this initialize the library and check potential ABI mismatches
* between the version it was compiled for and the actual shared
* library used
*/
LIBXML_TEST_VERSION ;
2015-09-22 14:17:38 +00:00
2019-05-20 16:48:23 +00:00
/* parse "data" into a document (which is a libxml2 tree structure xmlDoc) */
doc = xmlReadMemory ( data , size , " noname.xml " , NULL , XML_PARSE_NONET ) ;
if ( doc = = NULL ) {
GST_ERROR ( " failed to parse the MPD file " ) ;
ret = FALSE ;
} else {
/* get the root element node */
root_element = xmlDocGetRootElement ( doc ) ;
2013-02-22 19:40:36 +00:00
2019-05-20 16:48:23 +00:00
if ( root_element - > type ! = XML_ELEMENT_NODE
| | xmlStrcmp ( root_element - > name , ( xmlChar * ) " MPD " ) ! = 0 ) {
GST_ERROR
( " can not find the root element MPD, failed to parse the MPD file " ) ;
ret = FALSE ; /* used to return TRUE before, but this seems wrong */
} else {
/* now we can parse the MPD root node and all children nodes, recursively */
2019-05-24 14:24:00 +00:00
ret = gst_mpdparser_parse_root_node ( mpd_root_node , root_element ) ;
2019-05-20 16:48:23 +00:00
}
/* free the document */
xmlFreeDoc ( doc ) ;
2013-02-22 19:40:36 +00:00
}
}
return ret ;
}
2019-05-24 14:24:00 +00:00
GstMPDSegmentListNode *
2019-05-20 16:48:23 +00:00
gst_mpdparser_get_external_segment_list ( const gchar * data , gint size ,
2019-05-24 14:24:00 +00:00
GstMPDSegmentListNode * parent )
2012-10-24 09:49:51 +00:00
{
2019-05-20 16:48:23 +00:00
xmlDocPtr doc = NULL ;
2019-05-24 14:24:00 +00:00
GstMPDSegmentListNode * new_segment_list = NULL ;
2012-10-24 09:49:51 +00:00
2019-05-20 16:48:23 +00:00
doc = xmlReadMemory ( data , size , " noname.xml " , NULL , XML_PARSE_NONET ) ;
2012-10-24 09:49:51 +00:00
2015-09-22 14:17:38 +00:00
2019-05-20 16:48:23 +00:00
/* NOTE: ISO/IEC 23009-1:2014 5.3.9.3.2 is saying that one or multiple SegmentList
* in external xml is allowed , however , multiple SegmentList does not make sense
* because Period / AdaptationSet / Representation allow only one SegmentList */
if ( doc ) {
xmlNode * root_element = xmlDocGetRootElement ( doc ) ;
2012-10-24 09:49:51 +00:00
2019-05-20 16:48:23 +00:00
if ( root_element - > type = = XML_ELEMENT_NODE & &
xmlStrcmp ( root_element - > name , ( xmlChar * ) " SegmentList " ) = = 0 ) {
gst_mpdparser_parse_segment_list_node ( & new_segment_list , root_element ,
parent ) ;
}
}
2012-12-17 14:19:33 +00:00
2019-05-20 16:48:23 +00:00
if ( doc )
xmlFreeDoc ( doc ) ;
2012-12-17 14:19:33 +00:00
2019-05-20 16:48:23 +00:00
return new_segment_list ;
2012-12-17 14:04:45 +00:00
}
2019-05-20 16:48:23 +00:00
GList *
gst_mpdparser_get_external_periods ( const gchar * data , gint size )
2013-02-22 19:40:36 +00:00
{
2019-05-20 16:48:23 +00:00
xmlDocPtr doc = NULL ;
GList * new_periods = NULL ;
2013-02-22 19:40:36 +00:00
2019-05-20 16:48:23 +00:00
doc = xmlReadMemory ( data , size , " noname.xml " , NULL , XML_PARSE_NONET ) ;
2013-02-22 19:40:36 +00:00
2014-08-26 19:45:46 +00:00
2019-05-20 16:48:23 +00:00
if ( doc ) {
xmlNode * root_element = xmlDocGetRootElement ( doc ) ;
xmlNode * iter ;
2015-10-07 13:22:46 +00:00
2019-05-20 16:48:23 +00:00
for ( iter = root_element - > children ; iter ; iter = iter - > next ) {
if ( iter - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrcmp ( iter - > name , ( xmlChar * ) " Period " ) = = 0 ) {
gst_mpdparser_parse_period_node ( & new_periods , iter ) ;
} else {
goto error ;
}
}
}
}
2014-08-26 19:45:46 +00:00
2019-05-20 16:48:23 +00:00
done :
if ( doc )
xmlFreeDoc ( doc ) ;
2014-08-26 19:45:46 +00:00
2019-05-20 16:48:23 +00:00
return new_periods ;
2013-01-29 18:58:50 +00:00
2019-05-20 16:48:23 +00:00
error :
GST_ERROR ( " Failed to parse period node XML " ) ;
2015-10-07 13:22:46 +00:00
2019-05-20 16:48:23 +00:00
if ( new_periods ) {
2019-05-24 14:24:00 +00:00
g_list_free_full ( new_periods , ( GDestroyNotify ) gst_mpd_period_node_free ) ;
2019-05-20 16:48:23 +00:00
new_periods = NULL ;
}
goto done ;
2013-01-29 18:58:50 +00:00
}
2019-05-20 16:48:23 +00:00
GList *
gst_mpdparser_get_external_adaptation_sets ( const gchar * data , gint size ,
2019-05-24 14:24:00 +00:00
GstMPDPeriodNode * period )
2015-05-08 19:31:44 +00:00
{
2019-05-20 16:48:23 +00:00
xmlDocPtr doc = NULL ;
GList * new_adaptation_sets = NULL ;
2015-05-08 19:31:44 +00:00
2019-05-20 16:48:23 +00:00
doc = xmlReadMemory ( data , size , " noname.xml " , NULL , XML_PARSE_NONET ) ;
2015-05-08 19:31:44 +00:00
2019-05-20 16:48:23 +00:00
/* NOTE: ISO/IEC 23009-1:2014 5.3.3.2 is saying that exactly one AdaptationSet
* in external xml is allowed */
if ( doc ) {
xmlNode * root_element = xmlDocGetRootElement ( doc ) ;
if ( root_element - > type = = XML_ELEMENT_NODE & &
xmlStrcmp ( root_element - > name , ( xmlChar * ) " AdaptationSet " ) = = 0 ) {
gst_mpdparser_parse_adaptation_set_node ( & new_adaptation_sets ,
root_element , period ) ;
2015-05-08 19:31:44 +00:00
}
}
2013-02-22 19:40:36 +00:00
2019-05-20 16:48:23 +00:00
if ( doc )
xmlFreeDoc ( doc ) ;
2015-06-05 12:10:43 +00:00
2019-05-20 16:48:23 +00:00
return new_adaptation_sets ;
2013-02-22 19:40:36 +00:00
}
2019-05-20 16:48:23 +00:00
void
gst_mpdparser_free_stream_period ( GstStreamPeriod * stream_period )
2012-10-08 15:43:14 +00:00
{
2019-05-20 16:48:23 +00:00
if ( stream_period ) {
g_slice_free ( GstStreamPeriod , stream_period ) ;
}
2012-10-19 18:12:09 +00:00
}
2019-05-20 16:48:23 +00:00
void
gst_mpdparser_free_media_segment ( GstMediaSegment * media_segment )
2012-10-19 18:12:09 +00:00
{
2019-05-20 16:48:23 +00:00
if ( media_segment ) {
g_slice_free ( GstMediaSegment , media_segment ) ;
2012-10-19 18:12:09 +00:00
}
}
2019-05-20 16:48:23 +00:00
void
gst_mpdparser_init_active_stream_segments ( GstActiveStream * stream )
2012-12-17 14:39:10 +00:00
{
2019-05-20 16:48:23 +00:00
g_assert ( stream - > segments = = NULL ) ;
stream - > segments = g_ptr_array_new ( ) ;
g_ptr_array_set_free_func ( stream - > segments ,
( GDestroyNotify ) gst_mpdparser_free_media_segment ) ;
2012-12-17 14:39:10 +00:00
}
2019-05-20 16:48:23 +00:00
void
gst_mpdparser_free_active_stream ( GstActiveStream * active_stream )
2012-10-19 18:12:09 +00:00
{
2019-05-20 16:48:23 +00:00
if ( active_stream ) {
g_free ( active_stream - > baseURL ) ;
active_stream - > baseURL = NULL ;
g_free ( active_stream - > queryURL ) ;
active_stream - > queryURL = NULL ;
if ( active_stream - > segments )
g_ptr_array_unref ( active_stream - > segments ) ;
g_slice_free ( GstActiveStream , active_stream ) ;
2012-10-19 18:12:09 +00:00
}
2013-05-08 14:13:32 +00:00
}
2012-09-29 01:13:29 +00:00
2019-05-20 16:48:23 +00:00
const gchar *
gst_mpdparser_get_initializationURL ( GstActiveStream * stream ,
2019-12-04 16:25:24 +00:00
GstMPDURLTypeNode * InitializationURL )
2012-10-08 15:43:14 +00:00
{
2019-05-20 16:48:23 +00:00
const gchar * url_prefix ;
2012-10-19 18:12:09 +00:00
2019-05-20 16:48:23 +00:00
g_return_val_if_fail ( stream ! = NULL , NULL ) ;
2012-10-19 18:12:09 +00:00
2019-05-20 16:48:23 +00:00
url_prefix = ( InitializationURL
2019-05-24 14:24:00 +00:00
& & InitializationURL - > sourceURL ) ? InitializationURL - > sourceURL : stream - >
baseURL ;
2012-10-19 18:12:09 +00:00
2019-05-20 16:48:23 +00:00
return url_prefix ;
2013-05-08 14:13:32 +00:00
}
2019-05-20 16:48:23 +00:00
gchar *
gst_mpdparser_get_mediaURL ( GstActiveStream * stream ,
2019-05-24 14:24:00 +00:00
GstMPDSegmentURLNode * segmentURL )
2015-12-08 00:33:39 +00:00
{
2019-05-20 16:48:23 +00:00
const gchar * url_prefix ;
2015-12-08 00:33:39 +00:00
2019-05-20 16:48:23 +00:00
g_return_val_if_fail ( stream ! = NULL , NULL ) ;
g_return_val_if_fail ( segmentURL ! = NULL , NULL ) ;
2015-12-08 00:33:39 +00:00
2019-05-20 16:48:23 +00:00
url_prefix = segmentURL - > media ? segmentURL - > media : stream - > baseURL ;
g_return_val_if_fail ( url_prefix ! = NULL , NULL ) ;
2015-12-08 00:33:39 +00:00
2019-05-20 16:48:23 +00:00
return segmentURL - > media ;
}
2015-12-08 00:33:39 +00:00
2019-05-20 16:48:23 +00:00
/* navigation functions */
GstStreamMimeType
2019-05-24 14:24:00 +00:00
gst_mpdparser_representation_get_mimetype ( GstMPDAdaptationSetNode * adapt_set ,
GstMPDRepresentationNode * rep )
2019-05-20 16:48:23 +00:00
{
gchar * mime = NULL ;
2019-12-04 16:25:24 +00:00
if ( rep )
mime = GST_MPD_REPRESENTATION_BASE_NODE ( rep ) - > mimeType ;
if ( mime = = NULL ) {
mime = GST_MPD_REPRESENTATION_BASE_NODE ( adapt_set ) - > mimeType ;
2015-12-08 00:33:39 +00:00
}
2019-05-24 14:24:00 +00:00
if ( gst_mpd_helper_strncmp_ext ( mime , " audio " ) = = 0 )
2019-05-20 16:48:23 +00:00
return GST_STREAM_AUDIO ;
2019-05-24 14:24:00 +00:00
if ( gst_mpd_helper_strncmp_ext ( mime , " video " ) = = 0 )
2019-05-20 16:48:23 +00:00
return GST_STREAM_VIDEO ;
2019-05-24 14:24:00 +00:00
if ( gst_mpd_helper_strncmp_ext ( mime , " application " ) = = 0
| | gst_mpd_helper_strncmp_ext ( mime , " text " ) = = 0 )
2019-05-20 16:48:23 +00:00
return GST_STREAM_APPLICATION ;
return GST_STREAM_UNKNOWN ;
2015-12-08 00:33:39 +00:00
}
2019-05-20 16:48:23 +00:00
/* Helper methods */
gchar *
gst_mpdparser_build_URL_from_template ( const gchar * url_template ,
const gchar * id , guint number , guint bandwidth , guint64 time )
2012-10-08 15:43:14 +00:00
{
2019-05-20 16:48:23 +00:00
static const gchar default_format [ ] = " %01d " ;
gchar * * tokens , * token , * ret ;
const gchar * format ;
gint i , num_tokens ;
2012-10-19 18:12:09 +00:00
2019-05-20 16:48:23 +00:00
g_return_val_if_fail ( url_template ! = NULL , NULL ) ;
tokens = g_strsplit_set ( url_template , " $ " , - 1 ) ;
if ( ! tokens ) {
GST_WARNING ( " Scan of URL template failed! " ) ;
return NULL ;
}
num_tokens = g_strv_length ( tokens ) ;
2012-10-19 18:12:09 +00:00
2019-05-20 16:48:23 +00:00
/*
* each identifier is guarded by 2 $ , which means that we must have an odd number of tokens
* An even number of tokens means the string is not valid .
*/
if ( ( num_tokens & 1 ) = = 0 ) {
GST_ERROR ( " Invalid number of tokens (%d). url_template is '%s' " ,
num_tokens , url_template ) ;
g_strfreev ( tokens ) ;
return NULL ;
2012-10-19 18:12:09 +00:00
}
2019-05-20 16:48:23 +00:00
for ( i = 0 ; i < num_tokens ; i + + ) {
token = tokens [ i ] ;
format = default_format ;
2012-09-29 01:13:29 +00:00
2019-05-20 16:48:23 +00:00
/* the tokens to replace must be provided between $ characters, eg $token$
* For a string like token0 $ token1 $ token2 $ token3 $ token4 , only the odd number
* tokens ( 1 , 3 , . . . ) must be parsed .
*
* Skip even tokens
*/
if ( ( i & 1 ) = = 0 )
continue ;
2013-05-08 14:13:32 +00:00
2019-05-20 16:48:23 +00:00
if ( ! g_strcmp0 ( token , " RepresentationID " ) ) {
if ( ! gst_mpdparser_validate_rfc1738_url ( id ) )
goto invalid_representation_id ;
2012-10-02 00:28:58 +00:00
2019-05-20 16:48:23 +00:00
tokens [ i ] = g_strdup_printf ( " %s " , id ) ;
g_free ( token ) ;
} else if ( ! strncmp ( token , " Number " , 6 ) ) {
if ( strlen ( token ) > 6 ) {
format = token + 6 ; /* format tag */
2012-10-02 00:28:58 +00:00
}
2019-05-20 16:48:23 +00:00
if ( ! validate_format ( format ) )
goto invalid_format ;
2012-10-22 16:12:30 +00:00
2019-05-20 16:48:23 +00:00
tokens [ i ] = g_strdup_printf ( format , number ) ;
g_free ( token ) ;
} else if ( ! strncmp ( token , " Bandwidth " , 9 ) ) {
if ( strlen ( token ) > 9 ) {
format = token + 9 ; /* format tag */
}
if ( ! validate_format ( format ) )
goto invalid_format ;
2013-07-01 20:50:37 +00:00
2019-05-20 16:48:23 +00:00
tokens [ i ] = g_strdup_printf ( format , bandwidth ) ;
g_free ( token ) ;
} else if ( ! strncmp ( token , " Time " , 4 ) ) {
gchar * promoted_format ;
2013-09-26 19:13:33 +00:00
2019-05-20 16:48:23 +00:00
if ( strlen ( token ) > 4 ) {
format = token + 4 ; /* format tag */
}
if ( ! validate_format ( format ) )
goto invalid_format ;
2013-09-26 19:13:33 +00:00
2019-05-20 16:48:23 +00:00
promoted_format = promote_format_to_uint64 ( format ) ;
tokens [ i ] = g_strdup_printf ( promoted_format , time ) ;
g_free ( promoted_format ) ;
g_free ( token ) ;
} else if ( ! g_strcmp0 ( token , " " ) ) {
tokens [ i ] = g_strdup_printf ( " %s " , " $ " ) ;
g_free ( token ) ;
} else {
/* unexpected identifier found between $ signs
*
* " If the URL contains unescaped $ symbols which do not enclose a valid
* identifier then the result of URL formation is undefined "
*/
goto invalid_format ;
}
2018-10-16 15:57:30 +00:00
}
2013-09-26 19:13:33 +00:00
2019-05-20 16:48:23 +00:00
ret = g_strjoinv ( NULL , tokens ) ;
2015-11-10 22:00:58 +00:00
2019-05-20 16:48:23 +00:00
g_strfreev ( tokens ) ;
2015-11-10 22:00:58 +00:00
2019-05-20 16:48:23 +00:00
return ret ;
2015-11-10 22:00:58 +00:00
2019-05-20 16:48:23 +00:00
invalid_format :
{
GST_ERROR ( " Invalid format '%s' in '%s' " , format , token ) ;
g_strfreev ( tokens ) ;
2013-09-26 19:13:33 +00:00
2015-11-10 22:00:58 +00:00
return NULL ;
}
2019-05-20 16:48:23 +00:00
invalid_representation_id :
{
GST_ERROR
( " Representation ID string '%s' has characters invalid in an RFC 1738 URL " ,
id ) ;
2015-11-10 22:00:58 +00:00
2019-05-20 16:48:23 +00:00
g_strfreev ( tokens ) ;
2013-09-26 19:13:33 +00:00
2019-05-20 16:48:23 +00:00
return NULL ;
2013-07-09 02:24:28 +00:00
}
2013-07-01 20:50:37 +00:00
}