Skip to content

Commit

Permalink
Fix/mpd patch (#4457)
Browse files Browse the repository at this point in the history
* Add required changes to enable MPD patching with new XML parser
  • Loading branch information
dsilhavy committed Apr 16, 2024
1 parent 3138e16 commit b38ba81
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 77 deletions.
3 changes: 1 addition & 2 deletions externals/tXml.js
Expand Up @@ -150,7 +150,6 @@ export function translateEntitiesAndCharacterReferences(entitiesList, str) {
}

if (pos + 1) pos += 1

return children;
} else if (S.charCodeAt(pos + 1) === exclamationCC) {
if (S.charCodeAt(pos + 2) == minusCC) {
Expand Down Expand Up @@ -210,7 +209,6 @@ export function translateEntitiesAndCharacterReferences(entitiesList, str) {
// Transform/process on the fly child nodes to add them to their parent as an array or an object
if (parent) {
let tagName = node.tagName;
delete node.tagName;
if (nodesAsArray.indexOf(tagName) !== -1) {
if (!parent[tagName]) {
parent[tagName] = [];
Expand Down Expand Up @@ -360,6 +358,7 @@ export function translateEntitiesAndCharacterReferences(entitiesList, str) {
pos++;
}
// dash.js - BEGIN
node.__children = children;
return node;
// dash.js - END
}
Expand Down
4 changes: 2 additions & 2 deletions src/dash/DashAdapter.js
Expand Up @@ -904,7 +904,7 @@ function DashAdapter() {
// if the inserted element matches the operation target (not leaf) and there is a relative position we
// want the inserted position to be set such that our insertion is relative to original position
// since replace has modified the array length we reduce the insert point by 1
position = relativePosition + (insertBefore ? 0 : 1) + (operation.action == 'replace' ? -1 : 0);
position = relativePosition + (insertBefore ? 0 : 1) + (operation.action === 'replace' ? -1 : 0);
} else {
// otherwise we are in an add append/prepend case or replace case that removed the target name completely
position = insertBefore ? 0 : updatedNodes.length;
Expand Down Expand Up @@ -1188,7 +1188,6 @@ function DashAdapter() {

instance = {
applyPatchToManifest,
getMainAdaptationForType,
areMediaInfosEqual,
getAllMediaInfoForType,
getAvailabilityStartTime,
Expand All @@ -1207,6 +1206,7 @@ function DashAdapter() {
getIsTextTrack,
getIsTypeOf,
getLocation,
getMainAdaptationForType,
getManifestUpdatePeriod,
getMediaInfoForType,
getMpd,
Expand Down
2 changes: 1 addition & 1 deletion src/dash/models/DashManifestModel.js
Expand Up @@ -724,7 +724,7 @@ function DashManifestModel() {
voRepresentation.media = segmentInfo.media;
}
if (segmentInfo.hasOwnProperty(DashConstants.START_NUMBER)) {
voRepresentation.startNumber = segmentInfo.startNumber;
voRepresentation.startNumber = parseInt(segmentInfo.startNumber);
}
if (segmentInfo.hasOwnProperty(DashConstants.INDEX_RANGE)) {
voRepresentation.indexRange = segmentInfo.indexRange;
Expand Down
24 changes: 9 additions & 15 deletions src/dash/models/PatchManifestModel.js
Expand Up @@ -66,16 +66,15 @@ function PatchManifestModel() {
}

// Go through the patch operations in order and parse their actions out for usage
return (patch.__children || []).map((nodeContainer) => {
let action = Object.keys(nodeContainer)[0];
return (patch.__children || []).map((node) => {
const action = node.tagName;

// we only look add add/remove/replace actions
if (action !== 'add' && action !== 'remove' && action !== 'replace') {
logger.warn(`Ignoring node of invalid action: ${action}`);
return null;
}

let node = nodeContainer[action];
let selector = node.sel;

// add action can have special targeting via the 'type' attribute
Expand All @@ -101,16 +100,11 @@ function PatchManifestModel() {
value = node.__text || '';
} else if (action !== 'remove') {
value = node.__children.reduce((groups, child) => {
// note that this is informed by xml2js parse structure for the __children array
// which will be something like this for each child:
// {
// "<node-name>": { <xml2js-node-object> }
// }
let key = Object.keys(child)[0];
let key = child.tagName;
// we also ignore
if (key !== '#text') {
groups[key] = groups[key] || [];
groups[key].push(child[key]);
groups[key].push(child);
}
return groups;
}, {});
Expand All @@ -127,11 +121,11 @@ function PatchManifestModel() {
}

instance = {
getIsPatch: getIsPatch,
getPublishTime: getPublishTime,
getOriginalPublishTime: getOriginalPublishTime,
getMpdId: getMpdId,
getPatchOperations: getPatchOperations
getIsPatch,
getMpdId,
getOriginalPublishTime,
getPatchOperations,
getPublishTime
};

setup();
Expand Down
4 changes: 2 additions & 2 deletions src/streaming/ManifestUpdater.js
Expand Up @@ -207,13 +207,13 @@ function ManifestUpdater() {
let publishTime = adapter.getPublishTime(manifest);

// apply validated patch to manifest
patchSuccessful = adapter.applyPatchToManifest(manifest, patch);
adapter.applyPatchToManifest(manifest, patch);

// get the updated publish time
let updatedPublishTime = adapter.getPublishTime(manifest);

// ensure the patch properly updated the in-memory publish time
patchSuccessful = publishTime.getTime() != updatedPublishTime.getTime();
patchSuccessful = publishTime.getTime() !== updatedPublishTime.getTime();
}

// if the patch failed to apply, force a full manifest refresh
Expand Down
31 changes: 15 additions & 16 deletions test/unit/helpers/PatchHelper.js
@@ -1,7 +1,7 @@
import DashConstants from '../../../src/dash/constants/DashConstants.js';

function staticSElements() {
return [[0,10], [10,5], [15,10]].map(([t, d]) => {
return [[0, 10], [10, 5], [15, 10]].map(([t, d]) => {
return {
__children: [],
d: d,
Expand Down Expand Up @@ -44,7 +44,7 @@ function staticAdaptationSet(id) {
}

function staticBaseUrl(url, serviceLocation) {
if(!serviceLocation) {
if (!serviceLocation) {
return url;
}
return {
Expand Down Expand Up @@ -82,24 +82,23 @@ class PatchHelper {
[DashConstants.ORIGINAL_PUBLISH_TIME]: new Date().toISOString(),
// only the ordered child array is simulated
__children: operations.map((operation) => {
if (operation.action == 'add') {
if (operation.action === 'add') {
// add is special because it has extra possible attributes
return {
add: {
sel: operation.selector,
__children: operation.children,
__text: operation.text,
pos: operation.position,
type: operation.type
}
};
tagName: operation.action,
sel: operation.selector,
__children: operation.children,
__text: operation.text,
pos: operation.position,
type: operation.type
}

} else {
return {
[operation.action]: {
sel: operation.selector,
__children: operation.children,
__text: operation.text
}
tagName: operation.action,
sel: operation.selector,
__children: operation.children,
__text: operation.text
};
}
})
Expand Down
56 changes: 19 additions & 37 deletions test/unit/test/dash/dash.DashAdapter.js
Expand Up @@ -1146,13 +1146,11 @@ describe('DashAdapter', function () {

it('applies add operation to structure with no siblings', function () {
let manifest = {};
let addedPeriod = { id: 'foo' };
let addedPeriod = { id: 'foo', tagName: 'Period' };
let patch = patchHelper.generatePatch('foobar', [{
action: 'add',
selector: '/MPD',
children: [{
Period: addedPeriod
}]
children: [addedPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand All @@ -1161,18 +1159,16 @@ describe('DashAdapter', function () {
});

it('applies add operation to structure with single sibling', function () {
let originalPeriod = { id: 'foo' };
let addedPeriod = { id: 'bar' };
let originalPeriod = { id: 'foo', tagName: 'Period' };
let addedPeriod = { id: 'bar', tagName: 'Period' };
// special case x2js object which omits the variant
let manifest = {
Period: [originalPeriod]
};
let patch = patchHelper.generatePatch('foobar', [{
action: 'add',
selector: '/MPD',
children: [{
Period: addedPeriod
}]
children: [addedPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand All @@ -1182,16 +1178,14 @@ describe('DashAdapter', function () {

it('applies add implicit append operation with siblings', function () {
let originalPeriods = [{ id: 'foo' }, { id: 'bar' }];
let addedPeriod = { id: 'baz' };
let addedPeriod = { id: 'baz', tagName: 'Period' };
let manifest = {
Period: originalPeriods.slice()
};
let patch = patchHelper.generatePatch('foobar', [{
action: 'add',
selector: '/MPD',
children: [{
Period: addedPeriod
}]
children: [addedPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand All @@ -1201,17 +1195,15 @@ describe('DashAdapter', function () {

it('applies add prepend operation with siblings', function () {
let originalPeriods = [{ id: 'foo' }, { id: 'bar' }];
let addedPeriod = { id: 'baz' };
let addedPeriod = { id: 'baz', tagName: 'Period' };
let manifest = {
Period: originalPeriods.slice()
};
let patch = patchHelper.generatePatch('foobar', [{
action: 'add',
selector: '/MPD',
position: 'prepend',
children: [{
Period: addedPeriod
}]
children: [addedPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand All @@ -1221,17 +1213,15 @@ describe('DashAdapter', function () {

it('applies add before operation with siblings', function () {
let originalPeriods = [{ id: 'foo' }, { id: 'bar' }, { id: 'baz' }];
let addedPeriod = { id: 'qux' };
let addedPeriod = { id: 'qux', tagName: 'Period' };
let manifest = {
Period: originalPeriods.slice()
};
let patch = patchHelper.generatePatch('foobar', [{
action: 'add',
selector: '/MPD/Period[2]',
position: 'before',
children: [{
Period: addedPeriod
}]
children: [addedPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand All @@ -1241,17 +1231,15 @@ describe('DashAdapter', function () {

it('applies add after operation with siblings', function () {
let originalPeriods = [{ id: 'foo' }, { id: 'bar' }, { id: 'baz' }];
let addedPeriod = { id: 'qux' };
let addedPeriod = { id: 'qux', tagName: 'Period' };
let manifest = {
Period: originalPeriods.slice()
};
let patch = patchHelper.generatePatch('foobar', [{
action: 'add',
selector: '/MPD/Period[2]',
position: 'after',
children: [{
Period: addedPeriod
}]
children: [addedPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand Down Expand Up @@ -1295,16 +1283,14 @@ describe('DashAdapter', function () {

it('applies replace operation with siblings', function () {
let originalPeriods = [{ id: 'foo' }, { id: 'bar' }, { id: 'baz' }];
let replacementPeriod = { id: 'qux' };
let replacementPeriod = { id: 'qux', tagName: 'Period' };
let manifest = {
Period: originalPeriods.slice()
};
let patch = patchHelper.generatePatch('foobar', [{
action: 'replace',
selector: '/MPD/Period[2]',
children: [{
Period: replacementPeriod
}]
children: [replacementPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand All @@ -1314,16 +1300,14 @@ describe('DashAdapter', function () {

it('applies replace operation without siblings', function () {
let originalPeriod = { id: 'foo' };
let replacementPeriod = { id: 'bar' };
let replacementPeriod = { id: 'bar', tagName: 'Period' };
let manifest = {
Period: [originalPeriod]
};
let patch = patchHelper.generatePatch('foobar', [{
action: 'replace',
selector: '/MPD/Period[1]',
children: [{
Period: replacementPeriod
}]
children: [replacementPeriod]
}]);

dashAdapter.applyPatchToManifest(manifest, patch);
Expand Down Expand Up @@ -1410,7 +1394,7 @@ describe('DashAdapter', function () {

it('applies multiple operations respecting order', function () {
let originalPeriods = [{ id: 'foo' }, { id: 'bar' }];
let newPeriod = { id: 'baz' };
let newPeriod = { id: 'baz', tagName: 'Period' };
let manifest = {
Period: originalPeriods.slice()
};
Expand All @@ -1425,9 +1409,7 @@ describe('DashAdapter', function () {
action: 'add',
selector: '/MPD/Period[2]',
position: 'before',
children: [{
Period: newPeriod
}]
children: [newPeriod]
},
{
action: 'replace',
Expand Down
4 changes: 2 additions & 2 deletions test/unit/test/dash/dash.models.PatchManifestModel.js
Expand Up @@ -92,7 +92,7 @@ describe('PatchManifestModel', function () {
action: 'add',
selector: '/MPD/Period',
position: 'after',
children: [{ 'Period': {} }]
children: [{ tagName: 'Period' }]
}]);
let operations = patchManifestModel.getPatchOperations(patch);
expect(operations.length).to.equal(1);
Expand Down Expand Up @@ -137,7 +137,7 @@ describe('PatchManifestModel', function () {
let patch = patchHelper.generatePatch('foobar', [{
action: 'replace',
selector: '/MPD/Period',
children: [{ 'Period': {} }]
children: [{ tagName: 'Period' }]
}]);
let operations = patchManifestModel.getPatchOperations(patch);
expect(operations.length).to.equal(1);
Expand Down

0 comments on commit b38ba81

Please sign in to comment.