mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 02:31:03 +00:00
mpdparser: fixed parsing of SegmentList syntax element, and eliminated Represention node list from Period node
SegmentList nodes are allowed into Period, AdaptationSet or Representation nodes and there is at most 1 element, so no need to keep a list; Period nodes cannot have any Represention elements, as AdaptationSet nodes are mandatory; this breaks compatibility with some legacy DASH test sequences.
This commit is contained in:
parent
8e3092661a
commit
dd198bc86d
3 changed files with 49 additions and 39 deletions
|
@ -1069,7 +1069,7 @@ static gboolean
|
||||||
gst_dash_demux_switch_playlist (GstDashDemux * demux, guint64 bitrate)
|
gst_dash_demux_switch_playlist (GstDashDemux * demux, guint64 bitrate)
|
||||||
{
|
{
|
||||||
GstActiveStream *stream = NULL;
|
GstActiveStream *stream = NULL;
|
||||||
GList *rep_list;
|
GList *rep_list = NULL;
|
||||||
gint new_index;
|
gint new_index;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
@ -1083,8 +1083,8 @@ gst_dash_demux_switch_playlist (GstDashDemux * demux, guint64 bitrate)
|
||||||
/* retrieve representation list */
|
/* retrieve representation list */
|
||||||
if (stream->cur_adapt_set)
|
if (stream->cur_adapt_set)
|
||||||
rep_list = stream->cur_adapt_set->Representations;
|
rep_list = stream->cur_adapt_set->Representations;
|
||||||
else
|
if (!rep_list)
|
||||||
rep_list = demux->client->cur_period->Representations;
|
return FALSE;
|
||||||
|
|
||||||
/* get representation index with current max_bandwidth */
|
/* get representation index with current max_bandwidth */
|
||||||
new_index =
|
new_index =
|
||||||
|
|
|
@ -60,7 +60,7 @@ static void gst_mpdparser_parse_seg_base_type_ext (GstSegmentBaseType ** pointer
|
||||||
static void gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node);
|
static void gst_mpdparser_parse_s_node (GList ** list, xmlNode * a_node);
|
||||||
static void gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode ** pointer, xmlNode * a_node);
|
static void gst_mpdparser_parse_segment_timeline_node (GstSegmentTimelineNode ** pointer, xmlNode * a_node);
|
||||||
static void gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType ** pointer, xmlNode * a_node);
|
static void gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType ** pointer, xmlNode * a_node);
|
||||||
static void gst_mpdparser_parse_segment_list_node (GList ** list, xmlNode * a_node);
|
static void gst_mpdparser_parse_segment_list_node (GstSegmentListNode ** pointer, xmlNode * a_node);
|
||||||
static void gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType ** pointer, xmlNode * a_node);
|
static void gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType ** pointer, xmlNode * a_node);
|
||||||
static void gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node);
|
static void gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node);
|
||||||
static void gst_mpdparser_parse_adaptation_set_node (GList ** list, xmlNode * a_node);
|
static void gst_mpdparser_parse_adaptation_set_node (GList ** list, xmlNode * a_node);
|
||||||
|
@ -96,7 +96,7 @@ static GstRepresentationNode *gst_mpdparser_get_highest_representation (GList *
|
||||||
static GstRepresentationNode *gst_mpdparser_get_representation_with_max_bandwidth (GList * Representations, gint max_bandwidth);
|
static GstRepresentationNode *gst_mpdparser_get_representation_with_max_bandwidth (GList * Representations, gint max_bandwidth);
|
||||||
#endif
|
#endif
|
||||||
static GstSegmentBaseType *gst_mpdparser_get_segment_base (GstPeriodNode *Period, GstAdaptationSetNode * AdaptationSet, GstRepresentationNode * Representation);
|
static GstSegmentBaseType *gst_mpdparser_get_segment_base (GstPeriodNode *Period, GstAdaptationSetNode * AdaptationSet, GstRepresentationNode * Representation);
|
||||||
static GstSegmentListNode *gst_mpdparser_get_first_segment_list (GList * SegmentList);
|
static GstSegmentListNode *gst_mpdparser_get_segment_list (GstPeriodNode *Period, GstAdaptationSetNode * AdaptationSet, GstRepresentationNode * Representation);
|
||||||
|
|
||||||
/* Memory management */
|
/* Memory management */
|
||||||
static void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node);
|
static void gst_mpdparser_free_mpd_node (GstMPDNode * mpd_node);
|
||||||
|
@ -1092,17 +1092,17 @@ gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType ** pointer, x
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mpdparser_parse_segment_list_node (GList ** list, xmlNode * a_node)
|
gst_mpdparser_parse_segment_list_node (GstSegmentListNode ** pointer, xmlNode * a_node)
|
||||||
{
|
{
|
||||||
xmlNode *cur_node;
|
xmlNode *cur_node;
|
||||||
GstSegmentListNode *new_segment_list;
|
GstSegmentListNode *new_segment_list;
|
||||||
|
|
||||||
new_segment_list = g_slice_new0 (GstSegmentListNode);
|
gst_mpdparser_free_segment_list_node (*pointer);
|
||||||
|
*pointer = new_segment_list = g_slice_new0 (GstSegmentListNode);
|
||||||
if (new_segment_list == NULL) {
|
if (new_segment_list == NULL) {
|
||||||
GST_WARNING ("Allocation of SegmentList node failed!");
|
GST_WARNING ("Allocation of SegmentList node failed!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*list = g_list_append (*list, new_segment_list);
|
|
||||||
|
|
||||||
GST_LOG ("extension of SegmentList node:");
|
GST_LOG ("extension of SegmentList node:");
|
||||||
gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_list->MultSegBaseType, a_node);
|
gst_mpdparser_parse_mult_seg_base_type_ext (&new_segment_list->MultSegBaseType, a_node);
|
||||||
|
@ -1292,6 +1292,8 @@ gst_mpdparser_parse_adaptation_set_node (GList ** list, xmlNode * a_node)
|
||||||
gst_mpdparser_parse_baseURL_node (&new_adap_set->BaseURLs, cur_node);
|
gst_mpdparser_parse_baseURL_node (&new_adap_set->BaseURLs, cur_node);
|
||||||
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
|
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentBase") == 0) {
|
||||||
gst_mpdparser_parse_seg_base_type_ext (&new_adap_set->SegmentBase, cur_node);
|
gst_mpdparser_parse_seg_base_type_ext (&new_adap_set->SegmentBase, cur_node);
|
||||||
|
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentList") == 0) {
|
||||||
|
gst_mpdparser_parse_segment_list_node (&new_adap_set->SegmentList, cur_node);
|
||||||
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "ContentComponent") == 0) {
|
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "ContentComponent") == 0) {
|
||||||
gst_mpdparser_parse_content_component_node (&new_adap_set->ContentComponents, cur_node);
|
gst_mpdparser_parse_content_component_node (&new_adap_set->ContentComponents, cur_node);
|
||||||
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
|
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "SegmentTemplate") == 0) {
|
||||||
|
@ -1365,13 +1367,14 @@ gst_mpdparser_parse_period_node (GList ** list, xmlNode * a_node)
|
||||||
/* explore children nodes */
|
/* explore children nodes */
|
||||||
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
|
||||||
if (cur_node->type == XML_ELEMENT_NODE) {
|
if (cur_node->type == XML_ELEMENT_NODE) {
|
||||||
if (xmlStrcmp (cur_node->name, (xmlChar *) "Representation") == 0) {
|
if (xmlStrcmp (cur_node->name, (xmlChar *) "AdaptationSet") == 0) {
|
||||||
gst_mpdparser_parse_representation_node (&new_period->Representations, cur_node);
|
|
||||||
} else if (xmlStrcmp (cur_node->name, (xmlChar *) "AdaptationSet") == 0) {
|
|
||||||
gst_mpdparser_parse_adaptation_set_node (&new_period->AdaptationSets, cur_node);
|
gst_mpdparser_parse_adaptation_set_node (&new_period->AdaptationSets, cur_node);
|
||||||
} else if (xmlStrcmp (cur_node->name,
|
} else if (xmlStrcmp (cur_node->name,
|
||||||
(xmlChar *) "SegmentBase") == 0) {
|
(xmlChar *) "SegmentBase") == 0) {
|
||||||
gst_mpdparser_parse_seg_base_type_ext (&new_period->SegmentBase, cur_node);
|
gst_mpdparser_parse_seg_base_type_ext (&new_period->SegmentBase, cur_node);
|
||||||
|
} else if (xmlStrcmp (cur_node->name,
|
||||||
|
(xmlChar *) "SegmentList") == 0) {
|
||||||
|
gst_mpdparser_parse_segment_list_node (&new_period->SegmentList, cur_node);
|
||||||
} else if (xmlStrcmp (cur_node->name,
|
} else if (xmlStrcmp (cur_node->name,
|
||||||
(xmlChar *) "SegmentTemplate") == 0) {
|
(xmlChar *) "SegmentTemplate") == 0) {
|
||||||
gst_mpdparser_parse_segment_template_node (&new_period->SegmentTemplate, cur_node);
|
gst_mpdparser_parse_segment_template_node (&new_period->SegmentTemplate, cur_node);
|
||||||
|
@ -1782,16 +1785,20 @@ gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstSegmentListNode *
|
static GstSegmentListNode *
|
||||||
gst_mpdparser_get_first_segment_list (GList * SegmentList)
|
gst_mpdparser_get_segment_list (GstPeriodNode *Period,
|
||||||
|
GstAdaptationSetNode * AdaptationSet, GstRepresentationNode * Representation)
|
||||||
{
|
{
|
||||||
GList *list = NULL;
|
GstSegmentListNode *SegmentList = NULL;
|
||||||
|
|
||||||
if (SegmentList == NULL)
|
if (Representation && Representation->SegmentBase) {
|
||||||
return NULL;
|
SegmentList = Representation->SegmentList;
|
||||||
|
} else if (AdaptationSet) {
|
||||||
|
SegmentList = AdaptationSet->SegmentList;
|
||||||
|
} else {
|
||||||
|
SegmentList = Period->SegmentList;
|
||||||
|
}
|
||||||
|
|
||||||
list = g_list_first (SegmentList);
|
return SegmentList;
|
||||||
|
|
||||||
return list ? (GstSegmentListNode *) list->data : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* memory management functions */
|
/* memory management functions */
|
||||||
|
@ -1862,13 +1869,11 @@ gst_mpdparser_free_period_node (GstPeriodNode * period_node)
|
||||||
if (period_node) {
|
if (period_node) {
|
||||||
g_free (period_node->id);
|
g_free (period_node->id);
|
||||||
gst_mpdparser_free_seg_base_type_ext (period_node->SegmentBase);
|
gst_mpdparser_free_seg_base_type_ext (period_node->SegmentBase);
|
||||||
|
gst_mpdparser_free_segment_list_node (period_node->SegmentList);
|
||||||
gst_mpdparser_free_segment_template_node (period_node->SegmentTemplate);
|
gst_mpdparser_free_segment_template_node (period_node->SegmentTemplate);
|
||||||
g_list_foreach (period_node->AdaptationSets,
|
g_list_foreach (period_node->AdaptationSets,
|
||||||
(GFunc) gst_mpdparser_free_adaptation_set_node, NULL);
|
(GFunc) gst_mpdparser_free_adaptation_set_node, NULL);
|
||||||
g_list_free (period_node->AdaptationSets);
|
g_list_free (period_node->AdaptationSets);
|
||||||
g_list_foreach (period_node->Representations,
|
|
||||||
(GFunc) gst_mpdparser_free_representation_node, NULL);
|
|
||||||
g_list_free (period_node->Representations);
|
|
||||||
g_list_foreach (period_node->Subsets,
|
g_list_foreach (period_node->Subsets,
|
||||||
(GFunc) gst_mpdparser_free_subset_node, NULL);
|
(GFunc) gst_mpdparser_free_subset_node, NULL);
|
||||||
g_list_free (period_node->Subsets);
|
g_list_free (period_node->Subsets);
|
||||||
|
@ -1946,6 +1951,7 @@ gst_mpdparser_free_adaptation_set_node (GstAdaptationSetNode *
|
||||||
gst_mpdparser_free_representation_base_type
|
gst_mpdparser_free_representation_base_type
|
||||||
(adaptation_set_node->RepresentationBase);
|
(adaptation_set_node->RepresentationBase);
|
||||||
gst_mpdparser_free_seg_base_type_ext (adaptation_set_node->SegmentBase);
|
gst_mpdparser_free_seg_base_type_ext (adaptation_set_node->SegmentBase);
|
||||||
|
gst_mpdparser_free_segment_list_node (adaptation_set_node->SegmentList);
|
||||||
gst_mpdparser_free_segment_template_node (adaptation_set_node->SegmentTemplate);
|
gst_mpdparser_free_segment_template_node (adaptation_set_node->SegmentTemplate);
|
||||||
g_list_foreach (adaptation_set_node->BaseURLs,
|
g_list_foreach (adaptation_set_node->BaseURLs,
|
||||||
(GFunc) gst_mpdparser_free_base_url_node, NULL);
|
(GFunc) gst_mpdparser_free_base_url_node, NULL);
|
||||||
|
@ -1975,9 +1981,7 @@ gst_mpdparser_free_representation_node (GstRepresentationNode *
|
||||||
g_list_free (representation_node->SubRepresentations);
|
g_list_free (representation_node->SubRepresentations);
|
||||||
gst_mpdparser_free_seg_base_type_ext (representation_node->SegmentBase);
|
gst_mpdparser_free_seg_base_type_ext (representation_node->SegmentBase);
|
||||||
gst_mpdparser_free_segment_template_node (representation_node->SegmentTemplate);
|
gst_mpdparser_free_segment_template_node (representation_node->SegmentTemplate);
|
||||||
g_list_foreach (representation_node->SegmentList,
|
gst_mpdparser_free_segment_list_node (representation_node->SegmentList);
|
||||||
(GFunc) gst_mpdparser_free_segment_list_node, NULL);
|
|
||||||
g_list_free (representation_node->SegmentList);
|
|
||||||
g_list_foreach (representation_node->BaseURLs,
|
g_list_foreach (representation_node->BaseURLs,
|
||||||
(GFunc) gst_mpdparser_free_base_url_node, NULL);
|
(GFunc) gst_mpdparser_free_base_url_node, NULL);
|
||||||
g_list_free (representation_node->BaseURLs);
|
g_list_free (representation_node->BaseURLs);
|
||||||
|
@ -2416,7 +2420,12 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
||||||
GstClockTime PeriodStart = 0, PeriodEnd, start_time, duration;
|
GstClockTime PeriodStart = 0, PeriodEnd, start_time, duration;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
rep_list = stream->cur_adapt_set ? stream->cur_adapt_set->Representations : client->cur_period->Representations;
|
if (stream->cur_adapt_set == NULL) {
|
||||||
|
GST_WARNING ("No valid AdaptationSet node in the MPD file, aborting...");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rep_list = stream->cur_adapt_set->Representations;
|
||||||
stream->cur_representation = representation;
|
stream->cur_representation = representation;
|
||||||
stream->representation_idx = g_list_index (rep_list, representation);
|
stream->representation_idx = g_list_index (rep_list, representation);
|
||||||
|
|
||||||
|
@ -2457,7 +2466,7 @@ gst_mpd_client_setup_representation (GstMpdClient * client, GstActiveStream *str
|
||||||
|
|
||||||
/* get the first segment_list of the selected representation */
|
/* get the first segment_list of the selected representation */
|
||||||
if ((stream->cur_segment_list =
|
if ((stream->cur_segment_list =
|
||||||
gst_mpdparser_get_first_segment_list (representation->SegmentList)) == NULL) {
|
gst_mpdparser_get_segment_list (client->cur_period, stream->cur_adapt_set, representation)) == NULL) {
|
||||||
GST_WARNING ("No valid SegmentList node in the MPD file, aborting...");
|
GST_WARNING ("No valid SegmentList node in the MPD file, aborting...");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -2548,7 +2557,7 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
||||||
GstActiveStream *stream;
|
GstActiveStream *stream;
|
||||||
GstAdaptationSetNode *adapt_set;
|
GstAdaptationSetNode *adapt_set;
|
||||||
GstRepresentationNode *representation;
|
GstRepresentationNode *representation;
|
||||||
GList *rep_list;
|
GList *rep_list = NULL;
|
||||||
|
|
||||||
/* select a new period */
|
/* select a new period */
|
||||||
if (!client->cur_period)
|
if (!client->cur_period)
|
||||||
|
@ -2569,11 +2578,12 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
||||||
adapt_set =
|
adapt_set =
|
||||||
gst_mpdparser_get_first_adapt_set (client->cur_period->
|
gst_mpdparser_get_first_adapt_set (client->cur_period->
|
||||||
AdaptationSets);
|
AdaptationSets);
|
||||||
|
if (!adapt_set) {
|
||||||
|
GST_INFO ("No adaptation set found, aborting...");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
/* retrive the list of representations */
|
/* retrive the list of representations */
|
||||||
if (adapt_set != NULL)
|
rep_list = adapt_set->Representations;
|
||||||
rep_list = adapt_set->Representations;
|
|
||||||
else
|
|
||||||
rep_list = client->cur_period->Representations;
|
|
||||||
if (!rep_list) {
|
if (!rep_list) {
|
||||||
GST_WARNING ("Can not retrieve any representation, aborting...");
|
GST_WARNING ("Can not retrieve any representation, aborting...");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -2595,7 +2605,7 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
||||||
gst_mpdparser_get_first_adapt_set_with_mimeType (client->
|
gst_mpdparser_get_first_adapt_set_with_mimeType (client->
|
||||||
cur_period->AdaptationSets, "audio");
|
cur_period->AdaptationSets, "audio");
|
||||||
if (!adapt_set) {
|
if (!adapt_set) {
|
||||||
GST_INFO ("No audio adaptation set found");
|
GST_INFO ("No audio adaptation set found, aborting...");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
rep_list = adapt_set->Representations;
|
rep_list = adapt_set->Representations;
|
||||||
|
@ -2620,7 +2630,7 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
||||||
gst_mpdparser_get_first_adapt_set_with_mimeType (client->
|
gst_mpdparser_get_first_adapt_set_with_mimeType (client->
|
||||||
cur_period->AdaptationSets, "application");
|
cur_period->AdaptationSets, "application");
|
||||||
if (!adapt_set) {
|
if (!adapt_set) {
|
||||||
GST_INFO ("No application adaptation set found");
|
GST_INFO ("No application adaptation set found, aborting...");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
rep_list = adapt_set->Representations;
|
rep_list = adapt_set->Representations;
|
||||||
|
@ -2650,8 +2660,6 @@ gst_mpd_client_setup_streaming (GstMpdClient * client,
|
||||||
/* retrive representation list */
|
/* retrive representation list */
|
||||||
if (stream->cur_adapt_set != NULL)
|
if (stream->cur_adapt_set != NULL)
|
||||||
rep_list = stream->cur_adapt_set->Representations;
|
rep_list = stream->cur_adapt_set->Representations;
|
||||||
else
|
|
||||||
rep_list = client->cur_period->Representations;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* fast start */
|
/* fast start */
|
||||||
|
|
|
@ -239,8 +239,8 @@ struct _GstRepresentationNode
|
||||||
GstSegmentBaseType *SegmentBase;
|
GstSegmentBaseType *SegmentBase;
|
||||||
/* SegmentTemplate node */
|
/* SegmentTemplate node */
|
||||||
GstSegmentTemplateNode *SegmentTemplate;
|
GstSegmentTemplateNode *SegmentTemplate;
|
||||||
/* list of SegmentList nodes */
|
/* SegmentList node */
|
||||||
GList *SegmentList;
|
GstSegmentListNode *SegmentList;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstDescriptorType
|
struct _GstDescriptorType
|
||||||
|
@ -288,6 +288,8 @@ struct _GstAdaptationSetNode
|
||||||
GstRepresentationBaseType *RepresentationBase;
|
GstRepresentationBaseType *RepresentationBase;
|
||||||
/* SegmentBase node */
|
/* SegmentBase node */
|
||||||
GstSegmentBaseType *SegmentBase;
|
GstSegmentBaseType *SegmentBase;
|
||||||
|
/* SegmentList node */
|
||||||
|
GstSegmentListNode *SegmentList;
|
||||||
/* SegmentTemplate node */
|
/* SegmentTemplate node */
|
||||||
GstSegmentTemplateNode *SegmentTemplate;
|
GstSegmentTemplateNode *SegmentTemplate;
|
||||||
/* list of BaseURL nodes */
|
/* list of BaseURL nodes */
|
||||||
|
@ -312,13 +314,13 @@ struct _GstPeriodNode
|
||||||
gboolean bitstreamSwitching;
|
gboolean bitstreamSwitching;
|
||||||
/* SegmentBase node */
|
/* SegmentBase node */
|
||||||
GstSegmentBaseType *SegmentBase;
|
GstSegmentBaseType *SegmentBase;
|
||||||
|
/* SegmentList node */
|
||||||
|
GstSegmentListNode *SegmentList;
|
||||||
/* SegmentTemplate node */
|
/* SegmentTemplate node */
|
||||||
GstSegmentTemplateNode *SegmentTemplate;
|
GstSegmentTemplateNode *SegmentTemplate;
|
||||||
/* list of Adaptation Set nodes */
|
/* list of Adaptation Set nodes */
|
||||||
GList *AdaptationSets;
|
GList *AdaptationSets;
|
||||||
/* list of Representation nodes */
|
/* list of Representation nodes */
|
||||||
GList *Representations;
|
|
||||||
/* list of Subset nodes */
|
|
||||||
GList *Subsets;
|
GList *Subsets;
|
||||||
/* list of BaseURL nodes */
|
/* list of BaseURL nodes */
|
||||||
GList *BaseURLs;
|
GList *BaseURLs;
|
||||||
|
|
Loading…
Reference in a new issue