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.
1114 lines
24 KiB
1114 lines
24 KiB
import { |
|
toM3u8, |
|
generateSidxKey, |
|
addMediaSequenceValues, |
|
flattenMediaGroupPlaylists |
|
} from '../src/toM3u8'; |
|
import QUnit from 'qunit'; |
|
|
|
QUnit.module('toM3u8'); |
|
|
|
QUnit.test('playlists', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
id: '1', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
id: '2', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'text/vtt', |
|
type: 'static', |
|
baseUrl: 'https://www.example.com/vtt' |
|
} |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '2', |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'text/vtt', |
|
type: 'static', |
|
baseUrl: 'https://www.example.com/vtt' |
|
} |
|
}]; |
|
|
|
const expected = { |
|
allowCache: true, |
|
discontinuityStarts: [], |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
duration: 100, |
|
endList: true, |
|
mediaGroups: { |
|
AUDIO: { |
|
audio: { |
|
main: { |
|
autoselect: true, |
|
default: true, |
|
language: '', |
|
playlists: [{ |
|
attributes: { |
|
BANDWIDTH: 20000, |
|
CODECS: 'foo;bar', |
|
NAME: '1', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
endList: true, |
|
resolvedUri: '', |
|
segments: [], |
|
timeline: 0, |
|
uri: '', |
|
targetDuration: 0 |
|
}, { |
|
attributes: { |
|
BANDWIDTH: 10000, |
|
CODECS: 'foo;bar', |
|
NAME: '2', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
endList: true, |
|
resolvedUri: '', |
|
segments: [], |
|
timeline: 0, |
|
uri: '', |
|
targetDuration: 0 |
|
|
|
}], |
|
uri: '' |
|
} |
|
} |
|
}, |
|
['CLOSED-CAPTIONS']: {}, |
|
SUBTITLES: { |
|
subs: { |
|
text: { |
|
autoselect: false, |
|
default: false, |
|
language: 'text', |
|
playlists: [{ |
|
attributes: { |
|
BANDWIDTH: 20000, |
|
NAME: '1', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
targetDuration: 100, |
|
endList: true, |
|
resolvedUri: 'https://www.example.com/vtt', |
|
segments: [{ |
|
duration: 100, |
|
resolvedUri: 'https://www.example.com/vtt', |
|
timeline: 0, |
|
uri: 'https://www.example.com/vtt', |
|
number: 0 |
|
}], |
|
timeline: 0, |
|
uri: '' |
|
}, { |
|
attributes: { |
|
BANDWIDTH: 10000, |
|
NAME: '2', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
targetDuration: 100, |
|
endList: true, |
|
resolvedUri: 'https://www.example.com/vtt', |
|
segments: [{ |
|
duration: 100, |
|
resolvedUri: 'https://www.example.com/vtt', |
|
timeline: 0, |
|
uri: 'https://www.example.com/vtt', |
|
number: 0 |
|
}], |
|
timeline: 0, |
|
uri: '' |
|
}], |
|
uri: '' |
|
} |
|
} |
|
}, |
|
VIDEO: {} |
|
}, |
|
playlists: [{ |
|
attributes: { |
|
AUDIO: 'audio', |
|
SUBTITLES: 'subs', |
|
BANDWIDTH: 10000, |
|
CODECS: 'foo;bar', |
|
NAME: '1', |
|
['PROGRAM-ID']: 1, |
|
RESOLUTION: { |
|
height: 600, |
|
width: 800 |
|
} |
|
}, |
|
endList: true, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
targetDuration: 0, |
|
resolvedUri: '', |
|
segments: [], |
|
timeline: 0, |
|
uri: '' |
|
}], |
|
segments: [], |
|
uri: '' |
|
}; |
|
|
|
assert.deepEqual(toM3u8({ dashPlaylists }), expected); |
|
}); |
|
|
|
QUnit.test('playlists with segments', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
id: '1', |
|
codecs: 'foo;bar', |
|
duration: 2, |
|
sourceDuration: 100, |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'static' |
|
}, |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}] |
|
}, { |
|
attributes: { |
|
id: '2', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 2, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'static' |
|
}, |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
duration: 2, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static' |
|
}, |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
duration: 2, |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'text/vtt', |
|
type: 'static', |
|
baseUrl: 'https://www.example.com/vtt' |
|
}, |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
duration: 2, |
|
id: '2', |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'text/vtt', |
|
type: 'static', |
|
baseUrl: 'https://www.example.com/vtt' |
|
}, |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}] |
|
}]; |
|
|
|
const expected = { |
|
allowCache: true, |
|
discontinuityStarts: [], |
|
duration: 100, |
|
endList: true, |
|
mediaGroups: { |
|
AUDIO: { |
|
audio: { |
|
main: { |
|
autoselect: true, |
|
default: true, |
|
language: '', |
|
playlists: [{ |
|
attributes: { |
|
BANDWIDTH: 20000, |
|
CODECS: 'foo;bar', |
|
NAME: '1', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
targetDuration: 2, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
endList: true, |
|
resolvedUri: '', |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}], |
|
timeline: 0, |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
uri: '' |
|
}, { |
|
attributes: { |
|
BANDWIDTH: 10000, |
|
CODECS: 'foo;bar', |
|
NAME: '2', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
targetDuration: 2, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
endList: true, |
|
resolvedUri: '', |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}], |
|
timeline: 0, |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
uri: '' |
|
}], |
|
uri: '' |
|
} |
|
} |
|
}, |
|
['CLOSED-CAPTIONS']: {}, |
|
SUBTITLES: { |
|
subs: { |
|
text: { |
|
autoselect: false, |
|
default: false, |
|
language: 'text', |
|
playlists: [{ |
|
attributes: { |
|
BANDWIDTH: 20000, |
|
NAME: '1', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
endList: true, |
|
targetDuration: 2, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
resolvedUri: 'https://www.example.com/vtt', |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}], |
|
timeline: 0, |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
uri: '' |
|
}, { |
|
attributes: { |
|
BANDWIDTH: 10000, |
|
NAME: '2', |
|
['PROGRAM-ID']: 1 |
|
}, |
|
endList: true, |
|
targetDuration: 2, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
resolvedUri: 'https://www.example.com/vtt', |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}], |
|
timeline: 0, |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
uri: '' |
|
}], |
|
uri: '' |
|
} |
|
} |
|
}, |
|
VIDEO: {} |
|
}, |
|
playlists: [{ |
|
attributes: { |
|
AUDIO: 'audio', |
|
SUBTITLES: 'subs', |
|
BANDWIDTH: 10000, |
|
CODECS: 'foo;bar', |
|
NAME: '1', |
|
['PROGRAM-ID']: 1, |
|
RESOLUTION: { |
|
height: 600, |
|
width: 800 |
|
} |
|
}, |
|
endList: true, |
|
resolvedUri: '', |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
targetDuration: 2, |
|
segments: [{ |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 0 |
|
}, { |
|
uri: '', |
|
timeline: 0, |
|
duration: 2, |
|
resolvedUri: '', |
|
map: { |
|
uri: '', |
|
resolvedUri: '' |
|
}, |
|
number: 1 |
|
}], |
|
timeline: 0, |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
uri: '' |
|
}], |
|
segments: [], |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
uri: '' |
|
}; |
|
|
|
assert.deepEqual(toM3u8({ dashPlaylists }), expected); |
|
}); |
|
|
|
QUnit.test('playlists with sidx and sidxMapping', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static' |
|
}, |
|
segments: [], |
|
sidx: { |
|
byterange: { |
|
offset: 10, |
|
length: 10 |
|
}, |
|
uri: 'sidx.mp4', |
|
resolvedUri: 'http://example.com/sidx.mp4', |
|
timeline: 0, |
|
duration: 10 |
|
}, |
|
uri: 'http://example.com/fmp4.mp4' |
|
}]; |
|
|
|
const sidxMapping = { |
|
'sidx.mp4-10-19': { |
|
sidx: { |
|
timescale: 1, |
|
firstOffset: 0, |
|
references: [{ |
|
referenceType: 0, |
|
referencedSize: 5, |
|
subsegmentDuration: 2 |
|
}] |
|
} |
|
} |
|
}; |
|
|
|
const expected = [{ |
|
attributes: { |
|
AUDIO: 'audio', |
|
SUBTITLES: 'subs', |
|
BANDWIDTH: 10000, |
|
CODECS: 'foo;bar', |
|
NAME: '1', |
|
['PROGRAM-ID']: 1, |
|
RESOLUTION: { |
|
height: 600, |
|
width: 800 |
|
} |
|
}, |
|
sidx: { |
|
byterange: { |
|
offset: 10, |
|
length: 10 |
|
}, |
|
uri: 'sidx.mp4', |
|
resolvedUri: 'http://example.com/sidx.mp4', |
|
timeline: 0, |
|
duration: 10 |
|
}, |
|
targetDuration: 0, |
|
timeline: 0, |
|
timelineStarts: [{ start: 0, timeline: 0 }], |
|
uri: '', |
|
segments: [{ |
|
map: { |
|
resolvedUri: 'http://example.com/sidx.mp4', |
|
uri: '' |
|
}, |
|
byterange: { |
|
offset: 20, |
|
length: 5 |
|
}, |
|
uri: 'http://example.com/sidx.mp4', |
|
resolvedUri: 'http://example.com/sidx.mp4', |
|
duration: 2, |
|
number: 0, |
|
presentationTime: 0, |
|
timeline: 0 |
|
}], |
|
endList: true, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
discontinuityStarts: [], |
|
resolvedUri: '' |
|
}]; |
|
|
|
assert.deepEqual(toM3u8({ dashPlaylists, sidxMapping }).playlists, expected); |
|
}); |
|
|
|
QUnit.test('playlists without minimumUpdatePeriod dont assign default value', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static' |
|
}, |
|
segments: [], |
|
sidx: { |
|
byterange: { |
|
offset: 10, |
|
length: 10 |
|
}, |
|
uri: 'sidx.mp4', |
|
resolvedUri: 'http://example.com/sidx.mp4', |
|
duration: 10 |
|
}, |
|
uri: 'http://example.com/fmp4.mp4' |
|
}]; |
|
|
|
assert.equal(toM3u8({ dashPlaylists }).minimumUpdatePeriod, undefined); |
|
}); |
|
|
|
QUnit.test('playlists with minimumUpdatePeriod = 0', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static', |
|
minimumUpdatePeriod: 0 |
|
}, |
|
segments: [], |
|
sidx: { |
|
byterange: { |
|
offset: 10, |
|
length: 10 |
|
}, |
|
uri: 'sidx.mp4', |
|
resolvedUri: 'http://example.com/sidx.mp4', |
|
duration: 10 |
|
}, |
|
uri: 'http://example.com/fmp4.mp4' |
|
}]; |
|
|
|
assert.equal(toM3u8({ dashPlaylists }).minimumUpdatePeriod, 0); |
|
}); |
|
|
|
QUnit.test('playlists with integer value for minimumUpdatePeriod', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static', |
|
minimumUpdatePeriod: 2 |
|
}, |
|
segments: [], |
|
sidx: { |
|
byterange: { |
|
offset: 10, |
|
length: 10 |
|
}, |
|
uri: 'sidx.mp4', |
|
resolvedUri: 'http://example.com/sidx.mp4', |
|
duration: 10 |
|
}, |
|
uri: 'http://example.com/fmp4.mp4' |
|
}]; |
|
|
|
assert.equal( |
|
toM3u8({ dashPlaylists }).minimumUpdatePeriod, |
|
2000, |
|
'converts update period to ms' |
|
); |
|
}); |
|
|
|
QUnit.test('no playlists', function(assert) { |
|
assert.deepEqual(toM3u8({ dashPlaylists: [] }), {}); |
|
}); |
|
|
|
QUnit.test('dynamic playlists with suggestedPresentationDelay', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
id: '1', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'dynamic', |
|
suggestedPresentationDelay: 18 |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
id: '2', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'text/vtt', |
|
type: 'static', |
|
baseUrl: 'https://www.example.com/vtt' |
|
} |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'text/vtt', |
|
type: 'static', |
|
baseUrl: 'https://www.example.com/vtt' |
|
} |
|
}]; |
|
|
|
const output = toM3u8({ dashPlaylists }); |
|
|
|
assert.ok('suggestedPresentationDelay' in output); |
|
assert.deepEqual(output.suggestedPresentationDelay, 18); |
|
}); |
|
|
|
QUnit.test('playlists with label', function(assert) { |
|
const label = 'English with commentary'; |
|
const dashPlaylists = [{ |
|
attributes: { |
|
id: '1', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'dynamic', |
|
label |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
id: '2', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}]; |
|
const output = toM3u8({ dashPlaylists }); |
|
|
|
assert.ok(label in output.mediaGroups.AUDIO.audio, 'label exists'); |
|
}); |
|
|
|
QUnit.test('608 captions', function(assert) { |
|
const dashPlaylists = [{ |
|
attributes: { |
|
captionServices: [{ |
|
channel: 'CC1', |
|
language: 'CC1' |
|
}, { |
|
channel: 'CC2', |
|
language: 'CC2' |
|
}, { |
|
channel: undefined, |
|
language: 'English' |
|
}, { |
|
channel: 'CC4', |
|
language: 'eng' |
|
}], |
|
id: '1', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 20000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'dynamic' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
id: '2', |
|
codecs: 'foo;bar', |
|
sourceDuration: 100, |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'audio/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}, { |
|
attributes: { |
|
sourceDuration: 100, |
|
id: '1', |
|
width: 800, |
|
height: 600, |
|
codecs: 'foo;bar', |
|
duration: 0, |
|
bandwidth: 10000, |
|
periodStart: 0, |
|
mimeType: 'video/mp4', |
|
type: 'static' |
|
}, |
|
segments: [] |
|
}]; |
|
const output = toM3u8({ dashPlaylists }); |
|
|
|
const cc = output.mediaGroups['CLOSED-CAPTIONS'].cc; |
|
|
|
Object.keys(cc).forEach((key) => { |
|
assert.notOk(cc[key].autoselect, 'no autoselect'); |
|
assert.notOk(cc[key].default, 'no default'); |
|
}); |
|
|
|
assert.deepEqual(Object.keys(cc), ['CC1', 'CC2', 'English', 'eng'], 'we have 4 channels'); |
|
assert.equal(cc.CC1.instreamId, 'CC1', 'CC1 has an instreamId of CC1'); |
|
assert.equal(cc.CC2.instreamId, 'CC2', 'CC2 has an instreamId of CC1'); |
|
assert.equal(cc.English.instreamId, undefined, 'English captions dont have an instreamId'); |
|
assert.equal(cc.eng.instreamId, 'CC4', 'eng captions have an instreamId of CC4'); |
|
}); |
|
|
|
QUnit.module('generateSidxKey'); |
|
|
|
QUnit.test('generates correct key', function(assert) { |
|
const sidxInfo = { |
|
byterange: { |
|
offset: 1, |
|
length: 5 |
|
}, |
|
uri: 'uri' |
|
}; |
|
|
|
assert.strictEqual( |
|
generateSidxKey(sidxInfo), |
|
'uri-1-5', |
|
'the key byterange should have a inclusive end' |
|
); |
|
}); |
|
|
|
QUnit.module('addMediaSequenceValues'); |
|
|
|
QUnit.test('resets media sequence values', function(assert) { |
|
const playlists = [{ |
|
timeline: 17, |
|
mediaSequence: 2, |
|
discontinuitySequence: 3, |
|
segments: [{ |
|
number: 5, |
|
presentationTime: 17, |
|
timeline: 17 |
|
}, { |
|
number: 6, |
|
presentationTime: 19, |
|
timeline: 17 |
|
}, { |
|
number: 7, |
|
presentationTime: 21, |
|
timeline: 21 |
|
}] |
|
}, { |
|
timeline: 21, |
|
mediaSequence: 2, |
|
discontinuitySequence: 3, |
|
segments: [{ |
|
number: 1, |
|
presentationTime: 21, |
|
timeline: 21 |
|
}] |
|
}, { |
|
timeline: 17, |
|
mediaSequence: 2, |
|
discontinuitySequence: 2, |
|
segments: [] |
|
}]; |
|
const timelineStarts = [{ |
|
timeline: 17, |
|
start: 17 |
|
}, { |
|
timeline: 21, |
|
start: 21 |
|
}]; |
|
|
|
addMediaSequenceValues(playlists, timelineStarts); |
|
|
|
assert.deepEqual( |
|
playlists, |
|
[{ |
|
timeline: 17, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
segments: [{ |
|
number: 0, |
|
presentationTime: 17, |
|
timeline: 17 |
|
}, { |
|
number: 1, |
|
presentationTime: 19, |
|
timeline: 17 |
|
}, { |
|
number: 2, |
|
presentationTime: 21, |
|
timeline: 21 |
|
}] |
|
}, { |
|
timeline: 21, |
|
mediaSequence: 0, |
|
discontinuitySequence: 1, |
|
segments: [{ |
|
number: 0, |
|
presentationTime: 21, |
|
timeline: 21 |
|
}] |
|
}, { |
|
timeline: 17, |
|
mediaSequence: 0, |
|
discontinuitySequence: 0, |
|
segments: [] |
|
}], |
|
'updated media sequence values' |
|
); |
|
}); |
|
|
|
QUnit.module('flattenMediaGroupPlaylists'); |
|
|
|
QUnit.test('includes all media group playlists', function(assert) { |
|
assert.deepEqual( |
|
flattenMediaGroupPlaylists({ |
|
en: { |
|
playlists: [ |
|
{ attributes: { NAME: 'A' } }, |
|
{ attributes: { NAME: 'B' } } |
|
] |
|
}, |
|
es: { |
|
playlists: [ |
|
{ attributes: { NAME: 'C' } }, |
|
{ attributes: { NAME: 'D' } } |
|
] |
|
} |
|
}), |
|
[ |
|
{ attributes: { NAME: 'A' } }, |
|
{ attributes: { NAME: 'B' } }, |
|
{ attributes: { NAME: 'C' } }, |
|
{ attributes: { NAME: 'D' } } |
|
], |
|
'included all media group playlists' |
|
); |
|
});
|
|
|