You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1483 lines
30 KiB
1483 lines
30 KiB
import QUnit from 'qunit';
|
|
import {
|
|
constructTemplateUrl,
|
|
parseTemplateInfo,
|
|
segmentsFromTemplate
|
|
} from '../../src/segment/segmentTemplate';
|
|
|
|
QUnit.module('segmentTemplate - constructTemplateUrl');
|
|
|
|
QUnit.test('does not change url with no identifiers', function(assert) {
|
|
const url = 'path/to/segment.mp4';
|
|
|
|
assert.equal(constructTemplateUrl(url, {}), url, 'no change');
|
|
});
|
|
|
|
QUnit.test('replaces each identifier individually', function(assert) {
|
|
const values = {
|
|
RepresentationID: 'Rep1',
|
|
Bandwidth: 1000,
|
|
Number: 2,
|
|
Time: 2000
|
|
};
|
|
|
|
const cases = [
|
|
{
|
|
url: '/$RepresentationID$/segment.mp4',
|
|
expected: '/Rep1/segment.mp4'
|
|
},
|
|
{
|
|
url: '/$Bandwidth$/segment.mp4',
|
|
expected: '/1000/segment.mp4'
|
|
},
|
|
{
|
|
url: '/$Number$/segment.mp4',
|
|
expected: '/2/segment.mp4'
|
|
},
|
|
{
|
|
url: '/$Time$/segment.mp4',
|
|
expected: '/2000/segment.mp4'
|
|
},
|
|
{
|
|
url: '/$$/segment.mp4',
|
|
expected: '/$/segment.mp4'
|
|
}
|
|
];
|
|
|
|
cases.forEach(test => {
|
|
assert.equal(constructTemplateUrl(test.url, values), test.expected, `constructs ${test.url}`);
|
|
});
|
|
});
|
|
|
|
QUnit.test('replaces multiple identifiers in url', function(assert) {
|
|
assert.equal(
|
|
constructTemplateUrl(
|
|
'$$$Time$$$$$/$RepresentationID$/$Bandwidth$/$Number$-$Time$-segment-$Number$.mp4',
|
|
{
|
|
RepresentationID: 'Rep1',
|
|
Bandwidth: 1000,
|
|
Number: 2,
|
|
Time: 2000
|
|
}
|
|
),
|
|
'$2000$$/Rep1/1000/2-2000-segment-2.mp4',
|
|
'correctly replaces multiple identifiers in single url'
|
|
);
|
|
});
|
|
|
|
QUnit.test('does not replace unknown identifiers', function(assert) {
|
|
assert.equal(
|
|
constructTemplateUrl(
|
|
'/$UNKNOWN$/$RepresentationID$/$UNKOWN2$/$Number$.mp4',
|
|
{
|
|
RepresentationID: 'Rep1',
|
|
Number: 1
|
|
}
|
|
),
|
|
'/$UNKNOWN$/Rep1/$UNKOWN2$/1.mp4',
|
|
'ignores unknown identifiers'
|
|
);
|
|
});
|
|
|
|
QUnit.test('honors padding format tag', function(assert) {
|
|
assert.equal(
|
|
constructTemplateUrl(
|
|
'/$Number%03d$/segment.mp4',
|
|
{ Number: 7 }
|
|
),
|
|
'/007/segment.mp4',
|
|
'correctly adds padding when format tag present'
|
|
);
|
|
});
|
|
|
|
QUnit.test('does not add padding when value is longer than width', function(assert) {
|
|
assert.equal(
|
|
constructTemplateUrl(
|
|
'/$Bandwidth%06d$/segment.mp4',
|
|
{ Bandwidth: 999999999 }
|
|
),
|
|
'/999999999/segment.mp4',
|
|
'no padding when value longer than format width'
|
|
);
|
|
});
|
|
|
|
QUnit.test('does not use padding format tag for $RepresentationID$', function(assert) {
|
|
assert.equal(
|
|
constructTemplateUrl(
|
|
'/$RepresentationID%09d$/$Number%03d$/segment.mp4',
|
|
{ RepresentationID: 'Rep1', Number: 7 }
|
|
),
|
|
'/Rep1/007/segment.mp4',
|
|
'ignores format tag for $RepresentationID$'
|
|
);
|
|
});
|
|
|
|
QUnit.module('segmentTemplate - parseTemplateInfo');
|
|
|
|
QUnit.test(
|
|
'one media segment when no @duration attribute or SegmentTimeline element',
|
|
function(assert) {
|
|
const attributes = {
|
|
startNumber: 3,
|
|
timescale: 1000,
|
|
sourceDuration: 42,
|
|
periodIndex: 1
|
|
};
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, void 0),
|
|
[ { number: 3, duration: 42, time: 0, timeline: 1 }],
|
|
'creates segment list of one media segment when no @duration attribute or timeline'
|
|
);
|
|
}
|
|
);
|
|
|
|
QUnit.test('uses @duration attribute when present', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
timescale: 1000,
|
|
sourceDuration: 16,
|
|
duration: 6000,
|
|
periodIndex: 1
|
|
};
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, []),
|
|
[
|
|
{
|
|
number: 0,
|
|
duration: 6,
|
|
timeline: 1,
|
|
time: 0
|
|
},
|
|
{
|
|
number: 1,
|
|
duration: 6,
|
|
timeline: 1,
|
|
time: 6000
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 4,
|
|
timeline: 1,
|
|
time: 12000
|
|
}
|
|
],
|
|
'correctly parses segment durations and start times with @duration attribute'
|
|
);
|
|
});
|
|
|
|
QUnit.test('parseByDuration allows non zero startNumber', function(assert) {
|
|
const attributes = {
|
|
startNumber: 101,
|
|
timescale: 1000,
|
|
sourceDuration: 16,
|
|
duration: 6000,
|
|
periodIndex: 1
|
|
};
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, []),
|
|
[
|
|
{
|
|
number: 101,
|
|
duration: 6,
|
|
timeline: 1,
|
|
time: 0
|
|
},
|
|
{
|
|
number: 102,
|
|
duration: 6,
|
|
timeline: 1,
|
|
time: 6000
|
|
},
|
|
{
|
|
number: 103,
|
|
duration: 4,
|
|
timeline: 1,
|
|
time: 12000
|
|
}
|
|
],
|
|
'allows non zero startNumber'
|
|
);
|
|
});
|
|
|
|
QUnit.test('parseByDuration defaults 1 for startNumber and timescale', function(assert) {
|
|
const attributes = {
|
|
sourceDuration: 11,
|
|
duration: '4',
|
|
periodIndex: 1
|
|
};
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, []),
|
|
[
|
|
{
|
|
number: 1,
|
|
duration: 4,
|
|
timeline: 1,
|
|
time: 0
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 4,
|
|
timeline: 1,
|
|
time: 4
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 3,
|
|
timeline: 1,
|
|
time: 8
|
|
}
|
|
],
|
|
'uses default startNumber and timescale value of 1'
|
|
);
|
|
});
|
|
|
|
QUnit.test('parseByDuration uses endNumber and has correct duration', function(assert) {
|
|
const attributes = {
|
|
sourceDuration: 11,
|
|
duration: '4',
|
|
periodIndex: 1,
|
|
endNumber: '2'
|
|
};
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, []),
|
|
[
|
|
{
|
|
number: 1,
|
|
duration: 4,
|
|
timeline: 1,
|
|
time: 0
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 7,
|
|
timeline: 1,
|
|
time: 4
|
|
}
|
|
],
|
|
'uses default startNumber and timescale value of 1'
|
|
);
|
|
});
|
|
|
|
QUnit.test('uses SegmentTimeline info when no @duration attribute', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
t: 0,
|
|
d: 6000
|
|
},
|
|
{
|
|
d: 2000
|
|
},
|
|
{
|
|
d: 3000
|
|
},
|
|
{
|
|
d: 5000
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 0,
|
|
duration: 6,
|
|
time: 0,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 1,
|
|
duration: 2,
|
|
time: 6000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 3,
|
|
time: 8000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 5,
|
|
time: 11000,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'correctly calculates segment durations and start times with SegmentTimeline'
|
|
);
|
|
});
|
|
|
|
QUnit.test('parseByTimeline allows non zero startNumber', function(assert) {
|
|
const attributes = {
|
|
startNumber: 101,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
t: 0,
|
|
d: 6000
|
|
},
|
|
{
|
|
d: 2000
|
|
},
|
|
{
|
|
d: 3000
|
|
},
|
|
{
|
|
d: 5000
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 101,
|
|
duration: 6,
|
|
time: 0,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 102,
|
|
duration: 2,
|
|
time: 6000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 103,
|
|
duration: 3,
|
|
time: 8000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 104,
|
|
duration: 5,
|
|
time: 11000,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'allows non zero startNumber'
|
|
);
|
|
});
|
|
|
|
QUnit.test('parseByTimeline defaults 1 for startNumber and timescale', function(assert) {
|
|
const attributes = {
|
|
sourceDuration: 11,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
t: 0,
|
|
d: 4
|
|
},
|
|
{
|
|
d: 2
|
|
},
|
|
{
|
|
d: 3
|
|
},
|
|
{
|
|
d: 2
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 1,
|
|
duration: 4,
|
|
time: 0,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 2,
|
|
time: 4,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 3,
|
|
time: 6,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 4,
|
|
duration: 2,
|
|
time: 9,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'defaults to 1 for startNumber and timescale'
|
|
);
|
|
});
|
|
|
|
QUnit.test('defaults SegmentTimeline.S@t to 0 for first segment', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
d: 6000
|
|
},
|
|
{
|
|
d: 2000
|
|
},
|
|
{
|
|
d: 3000
|
|
},
|
|
{
|
|
d: 5000
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 0,
|
|
duration: 6,
|
|
time: 0,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 1,
|
|
duration: 2,
|
|
time: 6000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 3,
|
|
time: 8000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 5,
|
|
time: 11000,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'uses default value of 0'
|
|
);
|
|
});
|
|
|
|
QUnit.test('allows non zero starting SegmentTimeline.S@t value', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
t: 42000,
|
|
d: 6000
|
|
},
|
|
{
|
|
d: 2000
|
|
},
|
|
{
|
|
d: 3000
|
|
},
|
|
{
|
|
d: 5000
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 0,
|
|
duration: 6,
|
|
time: 42000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 1,
|
|
duration: 2,
|
|
time: 48000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 3,
|
|
time: 50000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 5,
|
|
time: 53000,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'allows non zero SegmentTimeline.S@t start value'
|
|
);
|
|
});
|
|
|
|
QUnit.test('honors @r repeat attribute for SegmentTimeline.S', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
t: 0,
|
|
d: 6000
|
|
},
|
|
{
|
|
d: 1000,
|
|
r: 3
|
|
},
|
|
{
|
|
d: 5000
|
|
},
|
|
{
|
|
d: 1000
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 0,
|
|
duration: 6,
|
|
time: 0,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 1,
|
|
duration: 1,
|
|
time: 6000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 1,
|
|
time: 7000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 1,
|
|
time: 8000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 4,
|
|
duration: 1,
|
|
time: 9000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 5,
|
|
duration: 5,
|
|
time: 10000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 6,
|
|
duration: 1,
|
|
time: 15000,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'correctly uses @r repeat attribute'
|
|
);
|
|
});
|
|
|
|
QUnit.test('correctly handles negative @r repeat value', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
t: 0,
|
|
d: 6000
|
|
},
|
|
{
|
|
d: 1000,
|
|
r: -1
|
|
},
|
|
{
|
|
t: 10000,
|
|
d: 5000
|
|
},
|
|
{
|
|
d: 1000
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 0,
|
|
duration: 6,
|
|
time: 0,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 1,
|
|
duration: 1,
|
|
time: 6000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 1,
|
|
time: 7000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 1,
|
|
time: 8000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 4,
|
|
duration: 1,
|
|
time: 9000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 5,
|
|
duration: 5,
|
|
time: 10000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 6,
|
|
duration: 1,
|
|
time: 15000,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'correctly uses negative @r repeat attribute'
|
|
);
|
|
});
|
|
|
|
QUnit.test('correctly handles negative @r repeat value for last S', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
sourceDuration: 15,
|
|
timescale: 1000,
|
|
periodIndex: 1
|
|
};
|
|
const segmentTimeline = [
|
|
{
|
|
t: 0,
|
|
d: 6000
|
|
},
|
|
{
|
|
d: 3000,
|
|
r: -1
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
parseTemplateInfo(attributes, segmentTimeline),
|
|
[
|
|
{
|
|
number: 0,
|
|
duration: 6,
|
|
time: 0,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 1,
|
|
duration: 3,
|
|
time: 6000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 2,
|
|
duration: 3,
|
|
time: 9000,
|
|
timeline: 1
|
|
},
|
|
{
|
|
number: 3,
|
|
duration: 3,
|
|
time: 12000,
|
|
timeline: 1
|
|
}
|
|
],
|
|
'correctly uses negative @r repeat attribute for last S'
|
|
);
|
|
});
|
|
|
|
QUnit.skip(
|
|
'detects discontinuity when @t time is greater than expected start time',
|
|
function(assert) {
|
|
|
|
}
|
|
);
|
|
|
|
QUnit.module('segmentTemplate - type ="dynamic"');
|
|
|
|
QUnit.test('correctly handles duration', function(assert) {
|
|
const basicAttributes = {
|
|
baseUrl: 'http://www.example.com/',
|
|
type: 'dynamic',
|
|
media: 'n-$Number$.m4s',
|
|
minimumUpdatePeriod: 0,
|
|
timescale: 1,
|
|
NOW: 10000,
|
|
clientOffset: 0,
|
|
availabilityStartTime: 0,
|
|
startNumber: 1,
|
|
duration: 2,
|
|
periodIndex: 1
|
|
};
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(basicAttributes, []),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 5,
|
|
resolvedUri: 'http://www.example.com/n-5.m4s',
|
|
timeline: 1,
|
|
uri: 'n-5.m4s'
|
|
}],
|
|
'segments correctly with basic settings'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(Object.assign({}, basicAttributes, { startNumber: 10 }), []),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 10,
|
|
resolvedUri: 'http://www.example.com/n-10.m4s',
|
|
timeline: 1,
|
|
uri: 'n-10.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 11,
|
|
resolvedUri: 'http://www.example.com/n-11.m4s',
|
|
timeline: 1,
|
|
uri: 'n-11.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 12,
|
|
resolvedUri: 'http://www.example.com/n-12.m4s',
|
|
timeline: 1,
|
|
uri: 'n-12.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 13,
|
|
resolvedUri: 'http://www.example.com/n-13.m4s',
|
|
timeline: 1,
|
|
uri: 'n-13.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 14,
|
|
resolvedUri: 'http://www.example.com/n-14.m4s',
|
|
timeline: 1,
|
|
uri: 'n-14.m4s'
|
|
}],
|
|
'segments adjusted correctly based on @startNumber'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(Object.assign(
|
|
{}, basicAttributes,
|
|
{ availabilityStartTime: 4 }
|
|
), []),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}],
|
|
'segments correct with @availabilityStartTime set'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(Object.assign(
|
|
{}, basicAttributes,
|
|
{ availabilityStartTime: 2, start: 4 }
|
|
), []),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}],
|
|
'segments correct with @availabilityStartTime and @start set'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(Object.assign(
|
|
{}, basicAttributes,
|
|
{ timeShiftBufferDepth: 4 }, []
|
|
)),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 5,
|
|
resolvedUri: 'http://www.example.com/n-5.m4s',
|
|
timeline: 1,
|
|
uri: 'n-5.m4s'
|
|
}],
|
|
'segments correct with @timeShiftBufferDepth set'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(Object.assign(
|
|
{}, basicAttributes,
|
|
{ clientOffset: -2000 }, []
|
|
)),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}],
|
|
'segments correct with given clientOffset'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(Object.assign(
|
|
{}, basicAttributes,
|
|
{ endNumber: '4' }, []
|
|
)),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}],
|
|
'segments correct with endNumber'
|
|
);
|
|
});
|
|
|
|
QUnit.test('correctly handles duration with segmentTimeline', function(assert) {
|
|
const basicAttributes = {
|
|
baseUrl: 'http://www.example.com/',
|
|
type: 'dynamic',
|
|
media: 'n-$Number$.m4s',
|
|
minimumUpdatePeriod: 2,
|
|
timescale: 1,
|
|
NOW: 8000,
|
|
clientOffset: 0,
|
|
availabilityStartTime: 0,
|
|
startNumber: 1,
|
|
periodIndex: 1
|
|
};
|
|
|
|
const segmentTimeline = [
|
|
{
|
|
t: 0,
|
|
d: 2,
|
|
r: 1
|
|
},
|
|
{
|
|
d: 2,
|
|
r: -1
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(basicAttributes, segmentTimeline),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 5,
|
|
resolvedUri: 'http://www.example.com/n-5.m4s',
|
|
timeline: 1,
|
|
uri: 'n-5.m4s'
|
|
}],
|
|
'segments should fill until current time when r = -1 and @minimumUpdatePeriod > 0'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(Object.assign({}, basicAttributes, {clientOffset: -2000}), segmentTimeline),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}],
|
|
'segments should fill correctly when taking client offset into account'
|
|
);
|
|
|
|
const segmentTimelineShifted = [
|
|
{
|
|
t: 2,
|
|
d: 2,
|
|
r: 1
|
|
},
|
|
{
|
|
d: 2,
|
|
r: -1
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(basicAttributes, segmentTimelineShifted),
|
|
[{
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}, {
|
|
duration: 2,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}],
|
|
'segments take into account different time value for first segment'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(
|
|
Object.assign({}, basicAttributes, {timescale: 2 }),
|
|
segmentTimelineShifted
|
|
),
|
|
[{
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 1,
|
|
resolvedUri: 'http://www.example.com/n-1.m4s',
|
|
timeline: 1,
|
|
uri: 'n-1.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 2,
|
|
resolvedUri: 'http://www.example.com/n-2.m4s',
|
|
timeline: 1,
|
|
uri: 'n-2.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 3,
|
|
resolvedUri: 'http://www.example.com/n-3.m4s',
|
|
timeline: 1,
|
|
uri: 'n-3.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 4,
|
|
resolvedUri: 'http://www.example.com/n-4.m4s',
|
|
timeline: 1,
|
|
uri: 'n-4.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 5,
|
|
resolvedUri: 'http://www.example.com/n-5.m4s',
|
|
timeline: 1,
|
|
uri: 'n-5.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 6,
|
|
resolvedUri: 'http://www.example.com/n-6.m4s',
|
|
timeline: 1,
|
|
uri: 'n-6.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 7,
|
|
resolvedUri: 'http://www.example.com/n-7.m4s',
|
|
timeline: 1,
|
|
uri: 'n-7.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 8,
|
|
resolvedUri: 'http://www.example.com/n-8.m4s',
|
|
timeline: 1,
|
|
uri: 'n-8.m4s'
|
|
}, {
|
|
duration: 1,
|
|
map: {
|
|
resolvedUri: 'http://www.example.com/',
|
|
uri: ''
|
|
},
|
|
number: 9,
|
|
resolvedUri: 'http://www.example.com/n-9.m4s',
|
|
timeline: 1,
|
|
uri: 'n-9.m4s'
|
|
}],
|
|
'segments take into account different time value for first segment with timescale'
|
|
);
|
|
});
|
|
|
|
QUnit.module('segmentTemplate - segmentsFromTemplate');
|
|
|
|
QUnit.test('constructs simple segment list and resolves uris', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
duration: 6000,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
bandwidth: 100,
|
|
id: 'Rep1',
|
|
initialization: {
|
|
sourceURL: '$RepresentationID$/$Bandwidth$/init.mp4'
|
|
},
|
|
media: '$RepresentationID$/$Bandwidth$/$Number%03d$-$Time%05d$.mp4',
|
|
periodIndex: 1,
|
|
baseUrl: 'https://example.com/'
|
|
};
|
|
const segments = [
|
|
{
|
|
duration: 6,
|
|
map: {
|
|
resolvedUri: 'https://example.com/Rep1/100/init.mp4',
|
|
uri: 'Rep1/100/init.mp4'
|
|
},
|
|
resolvedUri: 'https://example.com/Rep1/100/000-00000.mp4',
|
|
timeline: 1,
|
|
uri: 'Rep1/100/000-00000.mp4',
|
|
number: 0
|
|
},
|
|
{
|
|
duration: 6,
|
|
map: {
|
|
resolvedUri: 'https://example.com/Rep1/100/init.mp4',
|
|
uri: 'Rep1/100/init.mp4'
|
|
},
|
|
resolvedUri: 'https://example.com/Rep1/100/001-06000.mp4',
|
|
timeline: 1,
|
|
uri: 'Rep1/100/001-06000.mp4',
|
|
number: 1
|
|
},
|
|
{
|
|
duration: 4,
|
|
map: {
|
|
resolvedUri: 'https://example.com/Rep1/100/init.mp4',
|
|
uri: 'Rep1/100/init.mp4'
|
|
},
|
|
resolvedUri: 'https://example.com/Rep1/100/002-12000.mp4',
|
|
timeline: 1,
|
|
uri: 'Rep1/100/002-12000.mp4',
|
|
number: 2
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(attributes, void 0), segments,
|
|
'creates segments from template'
|
|
);
|
|
});
|
|
|
|
QUnit.test('constructs simple segment list and with <Initialization> node', function(assert) {
|
|
const attributes = {
|
|
startNumber: 0,
|
|
duration: 6000,
|
|
sourceDuration: 16,
|
|
timescale: 1000,
|
|
bandwidth: 100,
|
|
id: 'Rep1',
|
|
initialization: {
|
|
sourceURL: 'init.mp4',
|
|
range: '121-125'
|
|
},
|
|
media: '$RepresentationID$/$Bandwidth$/$Number%03d$-$Time%05d$.mp4',
|
|
periodIndex: 1,
|
|
baseUrl: 'https://example.com/'
|
|
};
|
|
const segments = [
|
|
{
|
|
duration: 6,
|
|
map: {
|
|
resolvedUri: 'https://example.com/init.mp4',
|
|
uri: 'init.mp4',
|
|
byterange: {
|
|
length: 5,
|
|
offset: 121
|
|
}
|
|
},
|
|
resolvedUri: 'https://example.com/Rep1/100/000-00000.mp4',
|
|
timeline: 1,
|
|
uri: 'Rep1/100/000-00000.mp4',
|
|
number: 0
|
|
},
|
|
{
|
|
duration: 6,
|
|
map: {
|
|
resolvedUri: 'https://example.com/init.mp4',
|
|
uri: 'init.mp4',
|
|
byterange: {
|
|
length: 5,
|
|
offset: 121
|
|
}
|
|
},
|
|
resolvedUri: 'https://example.com/Rep1/100/001-06000.mp4',
|
|
timeline: 1,
|
|
uri: 'Rep1/100/001-06000.mp4',
|
|
number: 1
|
|
},
|
|
{
|
|
duration: 4,
|
|
map: {
|
|
resolvedUri: 'https://example.com/init.mp4',
|
|
uri: 'init.mp4',
|
|
byterange: {
|
|
length: 5,
|
|
offset: 121
|
|
}
|
|
},
|
|
resolvedUri: 'https://example.com/Rep1/100/002-12000.mp4',
|
|
timeline: 1,
|
|
uri: 'Rep1/100/002-12000.mp4',
|
|
number: 2
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(
|
|
segmentsFromTemplate(attributes, void 0), segments,
|
|
'creates segments from template'
|
|
);
|
|
});
|