Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions src/inheritAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const buildBaseUrls = (references, baseUrlElements) => {
return references;
}

return flatten(references.map(function(reference) {
const resolvedUrls = flatten(references.map(function(reference) {
return baseUrlElements.map(function(baseUrlElement) {
const initialBaseUrl = getContent(baseUrlElement);
const resolvedBaseUrl = resolveUrl(reference.baseUrl, initialBaseUrl);
Expand All @@ -49,6 +49,25 @@ export const buildBaseUrls = (references, baseUrlElements) => {
return finalBaseUrl;
});
}));

// Absolute child BaseURLs do not resolve against the parent, so the product of
// N parent BaseURLs repeats that child URL N times. Keep one copy of each unique
// resolved BaseURL object so content-steering copies that differ by serviceLocation
// (or other attributes) are preserved.
// See: https://github.com/videojs/mpd-parser/issues/175
const seen = {};

return resolvedUrls.filter(function(url) {
const key = JSON.stringify(url);

if (seen[key]) {
return false;
}

seen[key] = true;

return true;
});
};

/**
Expand Down Expand Up @@ -630,13 +649,6 @@ export const inheritAttributes = (mpd, options = {}) => {
return {
locations: mpdAttributes.locations,
contentSteeringInfo: generateContentSteeringInformation(contentSteeringNodes, eventHandler),
// TODO: There are occurences where this `representationInfo` array contains undesired
// duplicates. This generally occurs when there are multiple BaseURL nodes that are
// direct children of the MPD node. When we attempt to resolve URLs from a combination of the
// parent BaseURL and a child BaseURL, and the value does not resolve,
// we end up returning the child BaseURL multiple times.
// We need to determine a way to remove these duplicates in a safe way.
// See: https://github.com/videojs/mpd-parser/pull/17#discussion_r162750527
representationInfo: flatten(periods.map(toAdaptationSets(mpdAttributes, mpdBaseUrls))),
eventStream: flatten(periods.map(toEventStream))
};
Expand Down
97 changes: 63 additions & 34 deletions test/inheritAttributes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,67 @@ QUnit.test('absolute BaseURL overwrites reference', function(assert) {
);
});

QUnit.test('absolute BaseURL is not duplicated across multiple references', function(assert) {
const reference = [
{ baseUrl: 'https://cdn1.example.com/' },
{ baseUrl: 'https://cdn2.example.com/' }
];
const node = [{ textContent: 'https://example.com/en.vtt' }];
const expected = [{ baseUrl: 'https://example.com/en.vtt' }];

assert.deepEqual(
buildBaseUrls(reference, node), expected,
'absolute url is not duplicated'
);
});

QUnit.test('absolute BaseURL does not duplicate when mixed with relative BaseURLs', function(assert) {
const reference = [
{ baseUrl: 'https://cdn1.example.com/' },
{ baseUrl: 'https://cdn2.example.com/' }
];
const nodes = [
{ textContent: 'bar/' },
{ textContent: 'https://example.com/en.vtt' }
];
const expected = [
{ baseUrl: 'https://cdn1.example.com/bar/' },
{ baseUrl: 'https://example.com/en.vtt' },
{ baseUrl: 'https://cdn2.example.com/bar/' }
];

assert.deepEqual(
buildBaseUrls(reference, nodes), expected,
'relative urls still combine with each reference'
);
});

QUnit.test('absolute BaseURLs with different serviceLocation are both kept', function(assert) {
const reference = [
{ baseUrl: 'https://cdn1.example.com/' },
{ baseUrl: 'https://cdn2.example.com/' }
];
const nodes = [
{
textContent: 'https://example.com/en.vtt',
attributes: [{ name: 'serviceLocation', value: 'alpha' }]
},
{
textContent: 'https://example.com/en.vtt',
attributes: [{ name: 'serviceLocation', value: 'beta' }]
}
];
const expected = [
{ baseUrl: 'https://example.com/en.vtt', serviceLocation: 'alpha' },
{ baseUrl: 'https://example.com/en.vtt', serviceLocation: 'beta' }
];

assert.deepEqual(
buildBaseUrls(reference, nodes), expected,
'distinct serviceLocation values are preserved'
);
});

QUnit.test('reference attributes are ignored when there is a BaseURL node', function(assert) {
const reference = [{ baseUrl: 'https://example.com', attributes: [{ name: 'test', value: 'wow' }] }];
const node = [{ textContent: 'https://foo.com/bar/' }];
Expand Down Expand Up @@ -869,22 +930,6 @@ QUnit.test('end to end - content steering - non resolvable base URLs', function(
template: {}
}
},
{
attributes: {
NOW,
bandwidth: 256,
baseUrl: 'https://example.com/en.vtt',
clientOffset: 0,
id: 'en',
lang: 'en',
mimeType: 'text/vtt',
periodStart: 0,
role: {},
sourceDuration: 0,
type: 'dyanmic'
},
segmentInfo: {}
},
{
attributes: {
NOW,
Expand All @@ -904,7 +949,7 @@ QUnit.test('end to end - content steering - non resolvable base URLs', function(
]
};

assert.equal(actual.representationInfo.length, 4);
assert.equal(actual.representationInfo.length, 3);
assert.deepEqual(actual, expected);
});

Expand Down Expand Up @@ -1388,26 +1433,10 @@ QUnit.test('end to end - alternate BaseURLs', function(assert) {
clientOffset: 0
},
segmentInfo: {}
}, {
attributes: {
bandwidth: 256,
baseUrl: 'https://example.com/en.vtt',
id: 'en',
lang: 'en',
mediaPresentationDuration: 30,
mimeType: 'text/vtt',
periodStart: 0,
role: {},
sourceDuration: 30,
type: 'static',
NOW,
clientOffset: 0
},
segmentInfo: {}
}]
};

assert.equal(actual.representationInfo.length, 6);
assert.equal(actual.representationInfo.length, 5);
assert.deepEqual(actual, expected);
});

Expand Down