Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
GSoC
GSoC2018
macOS
vlc
Commits
738ebc3c
Commit
738ebc3c
authored
Dec 17, 2014
by
François Cartegnie
🤞
Browse files
demux: dash: drop broken BasicCMParser
parent
e186a15e
Changes
5
Hide whitespace changes
Inline
Side-by-side
modules/stream_filter/Makefile.am
View file @
738ebc3c
...
...
@@ -39,8 +39,6 @@ libdash_plugin_la_SOURCES = \
stream_filter/dash/mpd/AdaptationSet.cpp
\
stream_filter/dash/mpd/AdaptationSet.h
\
stream_filter/dash/mpd/BaseUrl.h
\
stream_filter/dash/mpd/BasicCMParser.cpp
\
stream_filter/dash/mpd/BasicCMParser.h
\
stream_filter/dash/mpd/CommonAttributesElements.cpp
\
stream_filter/dash/mpd/CommonAttributesElements.h
\
stream_filter/dash/mpd/ContentDescription.cpp
\
...
...
modules/stream_filter/dash/mpd/BasicCMParser.cpp
deleted
100644 → 0
View file @
e186a15e
/*
* BasicCMParser.cpp
*****************************************************************************
* Copyright (C) 2010 - 2011 Klagenfurt University
*
* Created on: Aug 10, 2010
* Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
* Christian Timmerer <christian.timmerer@itec.uni-klu.ac.at>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include
"BasicCMParser.h"
#include
"mpd/ContentDescription.h"
#include
"mpd/SegmentInfoDefault.h"
#include
"mpd/SegmentTemplate.h"
#include
"mpd/SegmentTimeline.h"
#include
"xml/DOMHelper.h"
#include
<cstdlib>
#include
<sstream>
#include
<vlc_strings.h>
#include
<vlc_stream.h>
using
namespace
dash
::
mpd
;
using
namespace
dash
::
xml
;
BasicCMParser
::
BasicCMParser
(
Node
*
root_
,
stream_t
*
p_stream
)
:
IMPDParser
(
root_
,
NULL
,
p_stream
,
NULL
)
{
this
->
url
=
p_stream
->
psz_access
;
this
->
url
+=
"://"
;
//Only append without the mpd file.
std
::
string
path
=
p_stream
->
psz_path
;
size_t
it
=
path
.
find_last_of
(
'/'
,
path
.
length
()
-
1
);
if
(
it
!=
std
::
string
::
npos
)
this
->
url
.
append
(
path
,
0
,
it
);
else
this
->
url
+=
p_stream
->
psz_path
;
this
->
url
+=
'/'
;
}
BasicCMParser
::~
BasicCMParser
()
{
}
bool
BasicCMParser
::
parse
(
Profile
profile
)
{
const
std
::
map
<
std
::
string
,
std
::
string
>
attr
=
this
->
root
->
getAttributes
();
mpd
=
new
MPD
(
p_stream
,
profile
);
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
;
it
=
attr
.
find
(
"mediaPresentationDuration"
);
/*
Standard specifies a default of "On-Demand",
so anything that is not "Live" is "On-Demand"
*/
it
=
attr
.
find
(
"availabilityStartTime"
);
if
(
it
==
attr
.
end
()
&&
this
->
mpd
->
isLive
()
==
true
)
{
msg_Err
(
p_stream
,
"An @availabilityStartTime attribute must be specified when"
" the stream @type is Live"
);
return
false
;
}
#ifdef HAVE_STRPTIME
if
(
it
!=
attr
.
end
()
)
{
struct
tm
t
;
char
*
res
=
strptime
(
it
->
second
.
c_str
(),
"%Y-%m-%dT%T"
,
&
t
);
if
(
res
==
NULL
)
{
if
(
this
->
mpd
->
isLive
()
==
true
)
{
msg_Err
(
p_stream
,
"An @availabilityStartTime attribute must be specified when"
" the stream @type is Live"
);
return
false
;
}
}
else
this
->
mpd
->
setAvailabilityStartTime
(
mktime
(
&
t
)
);
}
it
=
attr
.
find
(
"availabilityEndTime"
);
if
(
it
!=
attr
.
end
()
)
{
struct
tm
t
;
char
*
res
=
strptime
(
it
->
second
.
c_str
(),
"%Y-%m-%dT%T"
,
&
t
);
if
(
res
!=
NULL
)
this
->
mpd
->
setAvailabilityEndTime
(
mktime
(
&
t
)
);
}
#endif
it
=
attr
.
find
(
"mediaPresentationDuration"
);
if
(
it
!=
attr
.
end
()
)
this
->
mpd
->
setDuration
(
str_duration
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"minimumUpdatePeriodMPD"
);
if
(
it
!=
attr
.
end
()
)
this
->
mpd
->
setMinUpdatePeriod
(
str_duration
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"minBufferTime"
);
if
(
it
!=
attr
.
end
()
)
this
->
mpd
->
setMinBufferTime
(
str_duration
(
it
->
second
.
c_str
()
)
);
if
(
this
->
mpd
->
isLive
()
)
{
//This value is undefined when using type "On-Demand"
it
=
attr
.
find
(
"timeshiftBufferDepth"
);
if
(
it
!=
attr
.
end
()
)
this
->
mpd
->
setTimeShiftBufferDepth
(
str_duration
(
it
->
second
.
c_str
()
)
);
}
this
->
setMPDBaseUrl
(
this
->
root
);
this
->
setPeriods
(
this
->
root
);
this
->
mpd
->
setProgramInformation
(
this
->
parseProgramInformation
()
);
return
true
;
}
void
BasicCMParser
::
parseSegmentTimeline
(
Node
*
node
,
SegmentInfoCommon
*
segmentInfo
)
{
Node
*
segmentTimelineNode
=
DOMHelper
::
getFirstChildElementByName
(
node
,
"SegmentTimeline"
);
if
(
segmentTimelineNode
)
{
SegmentTimeline
*
segmentTimeline
=
new
SegmentTimeline
;
std
::
vector
<
Node
*>
sNodes
=
DOMHelper
::
getChildElementByTagName
(
segmentTimelineNode
,
"S"
);
std
::
vector
<
Node
*>::
const_iterator
it
=
sNodes
.
begin
();
std
::
vector
<
Node
*>::
const_iterator
end
=
sNodes
.
end
();
while
(
it
!=
end
)
{
SegmentTimeline
::
Element
*
s
=
new
SegmentTimeline
::
Element
;
const
std
::
map
<
std
::
string
,
std
::
string
>
sAttr
=
(
*
it
)
->
getAttributes
();
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
sIt
;
sIt
=
sAttr
.
find
(
"t"
);
if
(
sIt
==
sAttr
.
end
()
)
{
msg_Err
(
p_stream
,
"'t' attribute is mandatory for every SegmentTimeline/S element"
);
delete
s
;
++
it
;
continue
;
}
s
->
t
=
atoll
(
sIt
->
second
.
c_str
()
);
sIt
=
sAttr
.
find
(
"d"
);
if
(
sIt
==
sAttr
.
end
()
)
{
msg_Err
(
p_stream
,
"'d' attribute is mandatory for every SegmentTimeline/S element"
);
delete
s
;
++
it
;
continue
;
}
s
->
d
=
atoll
(
sIt
->
second
.
c_str
()
);
sIt
=
sAttr
.
find
(
"r"
);
if
(
sIt
!=
sAttr
.
end
()
)
s
->
r
=
atoi
(
sIt
->
second
.
c_str
()
);
segmentTimeline
->
addElement
(
s
);
++
it
;
}
segmentInfo
->
setSegmentTimeline
(
segmentTimeline
);
}
}
void
BasicCMParser
::
parseSegmentInfoCommon
(
Node
*
node
,
SegmentInfoCommon
*
segmentInfo
)
{
const
std
::
map
<
std
::
string
,
std
::
string
>
attr
=
node
->
getAttributes
();
const
std
::
vector
<
Node
*>
baseUrls
=
DOMHelper
::
getChildElementByTagName
(
node
,
"BaseURL"
);
if
(
baseUrls
.
size
()
>
0
)
{
std
::
vector
<
Node
*>::
const_iterator
it
=
baseUrls
.
begin
();
std
::
vector
<
Node
*>::
const_iterator
end
=
baseUrls
.
end
();
while
(
it
!=
end
)
{
segmentInfo
->
appendBaseURL
(
(
*
it
)
->
getText
()
);
++
it
;
}
}
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
=
attr
.
begin
();
this
->
setInitSegment
(
node
,
segmentInfo
);
it
=
attr
.
find
(
"duration"
);
if
(
it
!=
attr
.
end
()
)
segmentInfo
->
setDuration
(
str_duration
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"startIndex"
);
if
(
it
!=
attr
.
end
()
)
segmentInfo
->
setStartIndex
(
atoi
(
it
->
second
.
c_str
()
)
);
this
->
parseSegmentTimeline
(
node
,
segmentInfo
);
}
void
BasicCMParser
::
parseSegmentInfoDefault
(
Node
*
node
,
AdaptationSet
*
group
)
{
Node
*
segmentInfoDefaultNode
=
DOMHelper
::
getFirstChildElementByName
(
node
,
"SegmentInfoDefault"
);
if
(
segmentInfoDefaultNode
!=
NULL
)
{
SegmentInfoDefault
*
segInfoDef
=
new
SegmentInfoDefault
;
this
->
parseSegmentInfoCommon
(
segmentInfoDefaultNode
,
segInfoDef
);
group
->
setSegmentInfoDefault
(
segInfoDef
);
}
}
void
BasicCMParser
::
setAdaptationSets
(
Node
*
root
,
Period
*
period
)
{
std
::
vector
<
Node
*>
adaptSets
=
DOMHelper
::
getElementByTagName
(
root
,
"AdaptationSet"
,
false
);
if
(
adaptSets
.
size
()
==
0
)
//In some old file, AdaptationSet may still be called Group
adaptSets
=
DOMHelper
::
getElementByTagName
(
root
,
"Group"
,
false
);
for
(
size_t
i
=
0
;
i
<
adaptSets
.
size
();
i
++
)
{
const
std
::
map
<
std
::
string
,
std
::
string
>
attr
=
adaptSets
.
at
(
i
)
->
getAttributes
();
AdaptationSet
*
adaptSet
=
new
AdaptationSet
(
period
);
if
(
this
->
parseCommonAttributesElements
(
adaptSets
.
at
(
i
),
adaptSet
,
NULL
)
==
false
)
{
delete
adaptSet
;
continue
;
}
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
=
attr
.
find
(
"subsegmentAlignmentFlag"
);
if
(
it
!=
attr
.
end
()
&&
it
->
second
==
"true"
)
adaptSet
->
setSubsegmentAlignmentFlag
(
true
);
//Otherwise it is false by default.
this
->
parseSegmentInfoDefault
(
adaptSets
.
at
(
i
),
adaptSet
);
this
->
setRepresentations
(
adaptSets
.
at
(
i
),
adaptSet
);
period
->
addAdaptationSet
(
adaptSet
);
}
}
void
BasicCMParser
::
parseTrickMode
(
Node
*
node
,
Representation
*
repr
)
{
std
::
vector
<
Node
*>
trickModes
=
DOMHelper
::
getElementByTagName
(
node
,
"TrickMode"
,
false
);
if
(
trickModes
.
size
()
==
0
)
return
;
if
(
trickModes
.
size
()
>
1
)
msg_Err
(
p_stream
,
"More than 1 TrickMode element. Only the first one will be used."
);
Node
*
trickModeNode
=
trickModes
[
0
];
TrickModeType
*
trickMode
=
new
TrickModeType
;
const
std
::
map
<
std
::
string
,
std
::
string
>
attr
=
trickModeNode
->
getAttributes
();
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
=
attr
.
find
(
"alternatePlayoutRate"
);
if
(
it
!=
attr
.
end
()
)
trickMode
->
setAlternatePlayoutRate
(
atoi
(
it
->
second
.
c_str
()
)
);
repr
->
setTrickMode
(
trickMode
);
}
void
BasicCMParser
::
setRepresentations
(
Node
*
root
,
AdaptationSet
*
group
)
{
std
::
vector
<
Node
*>
representations
=
DOMHelper
::
getElementByTagName
(
root
,
"Representation"
,
false
);
for
(
size_t
i
=
0
;
i
<
representations
.
size
();
i
++
)
{
const
std
::
map
<
std
::
string
,
std
::
string
>
attributes
=
representations
.
at
(
i
)
->
getAttributes
();
Representation
*
rep
=
new
Representation
(
group
,
getMPD
());
this
->
currentRepresentation
=
rep
;
if
(
this
->
parseCommonAttributesElements
(
representations
.
at
(
i
),
rep
,
group
)
==
false
)
{
delete
rep
;
continue
;
}
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
;
it
=
attributes
.
find
(
"id"
);
if
(
it
==
attributes
.
end
()
)
msg_Err
(
p_stream
,
"Missing mandatory attribute for Representation: @id"
);
else
rep
->
setId
(
it
->
second
);
it
=
attributes
.
find
(
"bandwidth"
);
if
(
it
==
attributes
.
end
()
)
{
msg_Err
(
p_stream
,
"Missing mandatory attribute for Representation: @bandwidth"
);
delete
rep
;
continue
;
}
rep
->
setBandwidth
(
atoi
(
it
->
second
.
c_str
()
)
);
it
=
attributes
.
find
(
"qualityRanking"
);
if
(
it
!=
attributes
.
end
()
)
rep
->
setQualityRanking
(
atoi
(
it
->
second
.
c_str
()
)
);
it
=
attributes
.
find
(
"dependencyId"
);
if
(
it
!=
attributes
.
end
()
)
this
->
handleDependencyId
(
rep
,
group
,
it
->
second
);
if
(
this
->
setSegmentInfo
(
representations
.
at
(
i
),
rep
)
==
false
)
{
delete
rep
;
continue
;
}
group
->
addRepresentation
(
rep
);
}
}
void
BasicCMParser
::
handleDependencyId
(
Representation
*
rep
,
const
AdaptationSet
*
adaptationSet
,
const
std
::
string
&
dependencyId
)
{
if
(
dependencyId
.
empty
()
==
true
)
return
;
std
::
istringstream
s
(
dependencyId
);
while
(
s
)
{
std
::
string
id
;
s
>>
id
;
const
Representation
*
dep
=
adaptationSet
->
getRepresentationById
(
id
);
if
(
dep
)
rep
->
addDependency
(
dep
);
}
}
bool
BasicCMParser
::
setSegmentInfo
(
Node
*
root
,
Representation
*
rep
)
{
Node
*
segmentInfo
=
DOMHelper
::
getFirstChildElementByName
(
root
,
"SegmentInfo"
);
if
(
segmentInfo
)
{
SegmentInfo
*
info
=
new
SegmentInfo
(
rep
);
this
->
parseSegmentInfoCommon
(
segmentInfo
,
info
);
//If we don't have any segment, there's no point keeping this SegmentInfo.
if
(
this
->
setSegments
(
segmentInfo
,
info
)
==
false
)
{
delete
info
;
return
false
;
}
rep
->
setSegmentInfo
(
info
);
return
true
;
}
msg_Err
(
p_stream
,
"Missing mandatory element: Representation/SegmentInfo"
);
return
false
;
}
Segment
*
BasicCMParser
::
parseSegment
(
Node
*
node
,
bool
init
)
{
const
std
::
map
<
std
::
string
,
std
::
string
>
attr
=
node
->
getAttributes
();
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
;
bool
isTemplate
=
false
;
Segment
*
seg
=
NULL
;
if
(
node
->
getName
()
==
"UrlTemplate"
)
isTemplate
=
true
;
it
=
attr
.
find
(
"sourceURL"
);
//FIXME: When not present, the sourceUrl attribute should be computed
//using BaseURL and the range attribute.
if
(
it
!=
attr
.
end
()
)
{
std
::
string
url
=
it
->
second
;
bool
runtimeToken
=
false
;
if
(
isTemplate
==
true
)
{
if
(
this
->
resolveUrlTemplates
(
url
,
runtimeToken
)
==
false
)
{
msg_Err
(
p_stream
,
"Failed to substitute URLTemplate identifier."
);
return
NULL
;
}
seg
=
new
SegmentTemplate
(
currentRepresentation
);
}
else
{
if
(
init
)
seg
=
new
InitSegment
(
currentRepresentation
);
else
seg
=
new
Segment
(
currentRepresentation
);
}
if
(
url
.
find
(
this
->
p_stream
->
psz_access
)
!=
0
)
//Relative url
url
=
this
->
url
+
url
;
seg
->
setSourceUrl
(
url
);
}
return
seg
;
}
ProgramInformation
*
BasicCMParser
::
parseProgramInformation
()
{
Node
*
pInfoNode
=
DOMHelper
::
getFirstChildElementByName
(
this
->
root
,
"ProgramInformation"
);
if
(
pInfoNode
==
NULL
)
return
NULL
;
ProgramInformation
*
pInfo
=
new
ProgramInformation
;
const
std
::
map
<
std
::
string
,
std
::
string
>
attr
=
pInfoNode
->
getAttributes
();
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
;
it
=
attr
.
find
(
"moreInformationURL"
);
if
(
it
!=
attr
.
end
()
)
pInfo
->
setMoreInformationUrl
(
it
->
second
);
Node
*
title
=
DOMHelper
::
getFirstChildElementByName
(
pInfoNode
,
"Title"
);
if
(
title
)
pInfo
->
setTitle
(
title
->
getText
()
);
Node
*
source
=
DOMHelper
::
getFirstChildElementByName
(
pInfoNode
,
"Source"
);
if
(
source
)
pInfo
->
setSource
(
source
->
getText
()
);
Node
*
copyright
=
DOMHelper
::
getFirstChildElementByName
(
pInfoNode
,
"copyright"
);
if
(
copyright
)
pInfo
->
setCopyright
(
copyright
->
getText
()
);
return
pInfo
;
}
void
BasicCMParser
::
setInitSegment
(
Node
*
root
,
SegmentInfoCommon
*
info
)
{
const
std
::
vector
<
Node
*>
initSeg
=
DOMHelper
::
getChildElementByTagName
(
root
,
"InitialisationSegmentURL"
);
if
(
initSeg
.
size
()
>
1
)
msg_Err
(
p_stream
,
"There could be at most one InitialisationSegmentURL per SegmentInfo"
" other InitialisationSegmentURL will be dropped."
);
if
(
initSeg
.
size
()
==
1
)
{
Segment
*
seg
=
parseSegment
(
initSeg
.
at
(
0
),
true
);
if
(
seg
!=
NULL
)
info
->
setInitialisationSegment
(
seg
);
}
}
bool
BasicCMParser
::
setSegments
(
Node
*
root
,
SegmentInfo
*
info
)
{
std
::
vector
<
Node
*>
segments
=
DOMHelper
::
getElementByTagName
(
root
,
"Url"
,
false
);
std
::
vector
<
Node
*>
segmentsTemplates
=
DOMHelper
::
getElementByTagName
(
root
,
"UrlTemplate"
,
false
);
if
(
segments
.
size
()
==
0
&&
segmentsTemplates
.
size
()
==
0
)
return
false
;
segments
.
insert
(
segments
.
end
(),
segmentsTemplates
.
begin
(),
segmentsTemplates
.
end
()
);
for
(
size_t
i
=
0
;
i
<
segments
.
size
();
i
++
)
{
Segment
*
seg
=
parseSegment
(
segments
.
at
(
i
)
);
if
(
seg
==
NULL
)
continue
;
info
->
addSegment
(
seg
);
}
return
true
;
}
bool
BasicCMParser
::
resolveUrlTemplates
(
std
::
string
&
url
,
bool
&
containRuntimeToken
)
{
size_t
it
=
url
.
find
(
'$'
);
containRuntimeToken
=
false
;
while
(
it
!=
std
::
string
::
npos
)
{
size_t
closing
=
url
.
find
(
'$'
,
it
+
1
);
if
(
closing
==
std
::
string
::
npos
)
{
msg_Err
(
p_stream
,
"Unmatched '$' in url template: %s"
,
url
.
c_str
()
);
return
false
;
}
std
::
string
token
=
std
::
string
(
url
,
it
,
closing
-
it
+
1
);
if
(
token
==
"$$"
)
{
url
.
replace
(
it
,
token
.
length
(),
"$"
);
it
=
closing
+
1
;
}
else
if
(
token
==
"$RepresentationID$"
)
{
if
(
this
->
currentRepresentation
->
getId
().
empty
()
==
false
)
{
msg_Err
(
p_stream
,
"Representation doesn't have an ID. Can't substitute"
" identifier $RepresentationID$"
);
return
false
;
}
url
.
replace
(
it
,
token
.
length
(),
this
->
currentRepresentation
->
getId
()
);
it
=
it
+
this
->
currentRepresentation
->
getId
().
length
();
}
else
if
(
token
==
"$Bandwidth$"
)
{
std
::
ostringstream
oss
;
oss
<<
this
->
currentRepresentation
->
getBandwidth
();
url
.
replace
(
it
,
token
.
length
(),
oss
.
str
()
);
it
=
it
+
oss
.
str
().
length
();
}
else
{
if
(
token
==
"$Index$"
||
token
==
"$Time$"
)
{
containRuntimeToken
=
true
;
it
=
it
+
token
.
length
();
}
else
{
msg_Err
(
p_stream
,
"Unhandled token %s"
,
token
.
c_str
()
);
return
false
;
}
}
it
=
url
.
find
(
'$'
,
it
);
}
return
true
;
}
void
BasicCMParser
::
parseContentDescriptor
(
Node
*
node
,
const
std
::
string
&
name
,
void
(
CommonAttributesElements
::*
addPtr
)(
ContentDescription
*
),
CommonAttributesElements
*
self
)
const
{
std
::
vector
<
Node
*>
descriptors
=
DOMHelper
::
getChildElementByTagName
(
node
,
name
);
if
(
descriptors
.
empty
()
==
true
)
return
;
std
::
vector
<
Node
*>::
const_iterator
it
=
descriptors
.
begin
();
std
::
vector
<
Node
*>::
const_iterator
end
=
descriptors
.
end
();
while
(
it
!=
end
)
{
const
std
::
map
<
std
::
string
,
std
::
string
>
attr
=
(
*
it
)
->
getAttributes
();
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
itAttr
=
attr
.
find
(
"schemeIdUri"
);
if
(
itAttr
==
attr
.
end
()
)
{
++
it
;
continue
;
}
ContentDescription
*
desc
=
new
ContentDescription
;
desc
->
setSchemeIdUri
(
itAttr
->
second
);
Node
*
schemeInfo
=
DOMHelper
::
getFirstChildElementByName
(
node
,
"SchemeInformation"
);
if
(
schemeInfo
!=
NULL
)
desc
->
setSchemeInformation
(
schemeInfo
->
getText
()
);
(
self
->*
addPtr
)(
desc
);
++
it
;
}
}
bool
BasicCMParser
::
parseCommonAttributesElements
(
Node
*
node
,
CommonAttributesElements
*
common
,
CommonAttributesElements
*
parent
)
const
{
const
std
::
map
<
std
::
string
,
std
::
string
>
&
attr
=
node
->
getAttributes
();
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
;
//Parse mandatory elements first.
it
=
attr
.
find
(
"mimeType"
);
if
(
it
==
attr
.
end
()
)
{
if
(
parent
&&
parent
->
getMimeType
().
empty
()
==
false
)
common
->
setMimeType
(
parent
->
getMimeType
()
);
else
if
(
node
->
getName
().
find
(
"Representation"
)
!=
std
::
string
::
npos
)
{
msg_Err
(
p_stream
,
"Missing mandatory attribute: @mimeType"
);
return
false
;
}
}
else
common
->
setMimeType
(
it
->
second
);
//Everything else is optionnal.
it
=
attr
.
find
(
"width"
);
if
(
it
!=
attr
.
end
()
)
common
->
setWidth
(
atoi
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"height"
);
if
(
it
!=
attr
.
end
()
)
common
->
setHeight
(
atoi
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"parx"
);
if
(
it
!=
attr
.
end
()
)
common
->
setParX
(
atoi
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"pary"
);
if
(
it
!=
attr
.
end
()
)
common
->
setParY
(
atoi
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"frameRate"
);
if
(
it
!=
attr
.
end
()
)
common
->
setFrameRate
(
atoi
(
it
->
second
.
c_str
()
)
);
it
=
attr
.
find
(
"lang"
);
if
(
it
!=
attr
.
end
()
&&
it
->
second
.
empty
()
==
false
)
{
std
::
istringstream
s
(
it
->
second
);
while
(
s
)
{
std
::
string
lang
;
s
>>
lang
;
common
->
addLang
(
lang
);
}
}
it
=
attr
.
find
(
"numberOfChannels"
);
if
(
it
!=
attr
.
end
()
)
{
std
::
istringstream
s
(
it
->
second
);
while
(
s
)
{