@@ -16,21 +16,21 @@ const keySystemsMap = {
1616/**
1717 * Builds a list of urls that is the product of the reference urls and BaseURL values
1818 *
19- * @param {string [] } referenceUrls
20- * List of reference urls to resolve to
19+ * @param {Object [] } references
20+ * List of objects containing the reference URL as well as its attributes
2121 * @param {Node[] } baseUrlElements
2222 * List of BaseURL nodes from the mpd
23- * @return {string [] }
24- * List of resolved urls
23+ * @return {Object [] }
24+ * List of objects with resolved urls and attributes
2525 */
26- export const buildBaseUrls = ( referenceUrls , baseUrlElements ) => {
26+ export const buildBaseUrls = ( references , baseUrlElements ) => {
2727 if ( ! baseUrlElements . length ) {
28- return referenceUrls ;
28+ return references ;
2929 }
3030
31- return flatten ( referenceUrls . map ( function ( reference ) {
31+ return flatten ( references . map ( function ( reference ) {
3232 return baseUrlElements . map ( function ( baseUrlElement ) {
33- return resolveUrl ( reference , getContent ( baseUrlElement ) ) ;
33+ return merge ( parseAttributes ( baseUrlElement ) , { baseUrl : resolveUrl ( reference . baseUrl , getContent ( baseUrlElement ) ) } ) ;
3434 } ) ;
3535 } ) ) ;
3636} ;
@@ -140,8 +140,9 @@ export const getSegmentInformation = (adaptationSet) => {
140140 *
141141 * @param {Object } adaptationSetAttributes
142142 * Contains attributes inherited by the AdaptationSet
143- * @param {string[] } adaptationSetBaseUrls
144- * Contains list of resolved base urls inherited by the AdaptationSet
143+ * @param {Object[] } adaptationSetBaseUrls
144+ * List of objects containing resolved base URLs and attributes
145+ * inherited by the AdaptationSet
145146 * @param {SegmentInformation } adaptationSetSegmentInfo
146147 * Contains Segment information for the AdaptationSet
147148 * @return {inheritBaseUrlsCallback }
@@ -158,7 +159,7 @@ export const inheritBaseUrls =
158159 return repBaseUrls . map ( baseUrl => {
159160 return {
160161 segmentInfo : merge ( adaptationSetSegmentInfo , representationSegmentInfo ) ,
161- attributes : merge ( attributes , { baseUrl } )
162+ attributes : merge ( attributes , baseUrl )
162163 } ;
163164 } ) ;
164165 } ;
@@ -340,8 +341,9 @@ export const toEventStream = (period) => {
340341 *
341342 * @param {Object } periodAttributes
342343 * Contains attributes inherited by the Period
343- * @param {string[] } periodBaseUrls
344- * Contains list of resolved base urls inherited by the Period
344+ * @param {Object[] } periodBaseUrls
345+ * Contains list of objects with resolved base urls and attributes
346+ * inherited by the Period
345347 * @param {string[] } periodSegmentInfo
346348 * Contains Segment Information at the period level
347349 * @return {toRepresentationsCallback }
@@ -421,8 +423,9 @@ export const toRepresentations =
421423 *
422424 * @param {Object } mpdAttributes
423425 * Contains attributes inherited by the mpd
424- * @param {string[] } mpdBaseUrls
425- * Contains list of resolved base urls inherited by the mpd
426+ * @param {Object[] } mpdBaseUrls
427+ * Contains list of objects with resolved base urls and attributes
428+ * inherited by the mpd
426429 * @return {toAdaptationSetsCallback }
427430 * Callback map function
428431 */
@@ -441,6 +444,41 @@ export const toAdaptationSets = (mpdAttributes, mpdBaseUrls) => (period, index)
441444 return flatten ( adaptationSets . map ( toRepresentations ( periodAttributes , periodBaseUrls , periodSegmentInfo ) ) ) ;
442445} ;
443446
447+ /**
448+ * Tranforms an array of content steering nodes into an object
449+ * containing CDN content steering information from the MPD manifest.
450+ *
451+ * For more information on the DASH spec for Content Steering parsing, see:
452+ * https://dashif.org/docs/DASH-IF-CTS-00XX-Content-Steering-Community-Review.pdf
453+ *
454+ * @param {Node[] } contentSteeringNodes
455+ * Content steering nodes
456+ * @param {Function } eventHandler
457+ * The event handler passed into the parser options to handle warnings
458+ * @return {Object }
459+ * Object containing content steering data
460+ */
461+ export const generateContentSteeringInformation = ( contentSteeringNodes , eventHandler ) => {
462+ // If there are more than one ContentSteering tags, throw an error
463+ if ( contentSteeringNodes . length > 1 ) {
464+ eventHandler ( { type : 'warn' , message : 'The MPD manifest should contain no more than one ContentSteering tag' } ) ;
465+ }
466+
467+ // Return a null value if there are no ContentSteering tags
468+ if ( ! contentSteeringNodes . length ) {
469+ return null ;
470+ }
471+
472+ const infoFromContentSteeringTag =
473+ merge ( { serverURL : getContent ( contentSteeringNodes [ 0 ] ) } , parseAttributes ( contentSteeringNodes [ 0 ] ) ) ;
474+
475+ // Converts `queryBeforeStart` to a boolean, as well as setting the default value
476+ // to `false` if it doesn't exist
477+ infoFromContentSteeringTag . queryBeforeStart = ( infoFromContentSteeringTag . queryBeforeStart === 'true' ) ;
478+
479+ return infoFromContentSteeringTag ;
480+ } ;
481+
444482/**
445483 * Gets Period@start property for a given period.
446484 *
@@ -518,7 +556,14 @@ export const inheritAttributes = (mpd, options = {}) => {
518556 const {
519557 manifestUri = '' ,
520558 NOW = Date . now ( ) ,
521- clientOffset = 0
559+ clientOffset = 0 ,
560+ // TODO: For now, we are expecting an eventHandler callback function
561+ // to be passed into the mpd parser as an option.
562+ // In the future, we should enable stream parsing by using the Stream class from vhs-utils.
563+ // This will support new features including a standardized event handler.
564+ // See the m3u8 parser for examples of how stream parsing is currently used for HLS parsing.
565+ // https://github.com/videojs/vhs-utils/blob/88d6e10c631e57a5af02c5a62bc7376cd456b4f5/src/stream.js#L9
566+ eventHandler = function ( ) { }
522567 } = options ;
523568 const periodNodes = findChildren ( mpd , 'Period' ) ;
524569
@@ -530,6 +575,7 @@ export const inheritAttributes = (mpd, options = {}) => {
530575
531576 const mpdAttributes = parseAttributes ( mpd ) ;
532577 const mpdBaseUrls = buildBaseUrls ( [ manifestUri ] , findChildren ( mpd , 'BaseURL' ) ) ;
578+ const contentSteeringNodes = findChildren ( mpd , 'ContentSteering' ) ;
533579
534580 // See DASH spec section 5.3.1.2, Semantics of MPD element. Default type to 'static'.
535581 mpdAttributes . type = mpdAttributes . type || 'static' ;
@@ -567,6 +613,14 @@ export const inheritAttributes = (mpd, options = {}) => {
567613
568614 return {
569615 locations : mpdAttributes . locations ,
616+ contentSteeringInfo : generateContentSteeringInformation ( contentSteeringNodes , eventHandler ) ,
617+ // TODO: There are occurences where this `representationInfo` array contains undesired
618+ // duplicates. This generally occurs when there are multiple BaseURL nodes that are
619+ // direct children of the MPD node. When we attempt to resolve URLs from a combination of the
620+ // parent BaseURL and a child BaseURL, and the value does not resolve,
621+ // we end up returning the child BaseURL multiple times.
622+ // We need to determine a way to remove these duplicates in a safe way.
623+ // See: https://github.com/videojs/mpd-parser/pull/17#discussion_r162750527
570624 representationInfo : flatten ( periods . map ( toAdaptationSets ( mpdAttributes , mpdBaseUrls ) ) ) ,
571625 eventStream : flatten ( periods . map ( toEventStream ) )
572626 } ;
0 commit comments