From 2211fa4802cbe55cc30d16d9dfd45fb8888f4663 Mon Sep 17 00:00:00 2001 From: wseymour15 Date: Mon, 21 Aug 2023 17:05:51 -0500 Subject: [PATCH 1/7] feat: improve serviceLocation for content steering --- src/inheritAttributes.js | 16 +- src/segment/segmentTemplate.js | 4 +- src/segment/urlType.js | 7 +- src/toM3u8.js | 2 + test/inheritAttributes.test.js | 13 +- test/toM3u8.test.js | 280 +++++++++++++++++++++++++++++++++ test/toPlaylists.test.js | 207 ++++++++++++++++++++++++ 7 files changed, 520 insertions(+), 9 deletions(-) diff --git a/src/inheritAttributes.js b/src/inheritAttributes.js index 84ec1dff..df6e4648 100644 --- a/src/inheritAttributes.js +++ b/src/inheritAttributes.js @@ -30,7 +30,21 @@ export const buildBaseUrls = (references, baseUrlElements) => { return flatten(references.map(function(reference) { return baseUrlElements.map(function(baseUrlElement) { - return merge(parseAttributes(baseUrlElement), { baseUrl: resolveUrl(reference.baseUrl, getContent(baseUrlElement)) }); + const initialBaseUrl = getContent(baseUrlElement); + const resolvedBaseUrl = resolveUrl(reference.baseUrl, initialBaseUrl); + + const finalBaseUrl = merge( + parseAttributes(baseUrlElement), + { baseUrl: resolvedBaseUrl } + ); + + // If the URL is resolved, we want to get the serviceLocation from the reference + // assuming there is no serviceLocation on the initialBaseUrl + if (resolvedBaseUrl !== initialBaseUrl) { + finalBaseUrl.serviceLocation = finalBaseUrl.serviceLocation || reference.serviceLocation; + } + + return finalBaseUrl; }); })); }; diff --git a/src/segment/segmentTemplate.js b/src/segment/segmentTemplate.js index 673887de..1158fa4b 100644 --- a/src/segment/segmentTemplate.js +++ b/src/segment/segmentTemplate.js @@ -147,7 +147,8 @@ export const segmentsFromTemplate = (attributes, segmentTimeline) => { const mapSegment = urlTypeToSegment({ baseUrl: attributes.baseUrl, source: constructTemplateUrl(initialization.sourceURL, templateValues), - range: initialization.range + range: initialization.range, + serviceLocation: attributes.serviceLocation }); const segments = parseTemplateInfo(attributes, segmentTimeline); @@ -172,6 +173,7 @@ export const segmentsFromTemplate = (attributes, segmentTimeline) => { timeline: segment.timeline, duration: segment.duration, resolvedUri: resolveUrl(attributes.baseUrl || '', uri), + serviceLocation: attributes.serviceLocation, map: mapSegment, number: segment.number, presentationTime diff --git a/src/segment/urlType.js b/src/segment/urlType.js index ae04f754..dd3caaff 100644 --- a/src/segment/urlType.js +++ b/src/segment/urlType.js @@ -23,13 +23,16 @@ import window from 'global/window'; * @param {string} source - source url for segment * @param {string} range - optional range used for range calls, * follows RFC 2616, Clause 14.35.1 + * @param {string} serviceLocation - optional serviceLocation provided by nodes + * used for content steering * @return {SingleUri} full segment information transformed into a format similar * to m3u8-parser */ -export const urlTypeToSegment = ({ baseUrl = '', source = '', range = '', indexRange = '' }) => { +export const urlTypeToSegment = ({ baseUrl = '', source = '', range = '', serviceLocation = null, indexRange = '' }) => { const segment = { uri: source, - resolvedUri: resolveUrl(baseUrl || '', source) + resolvedUri: resolveUrl(baseUrl || '', source), + serviceLocation }; if (range || indexRange) { diff --git a/src/toM3u8.js b/src/toM3u8.js index 01ba6255..e6ed2630 100644 --- a/src/toM3u8.js +++ b/src/toM3u8.js @@ -137,6 +137,7 @@ export const formatVttPlaylist = ({ timeline: attributes.periodStart, resolvedUri: attributes.baseUrl || '', duration: attributes.sourceDuration, + serviceLocation: attributes.serviceLocation, number: 0 }]; // targetDuration should be the same duration as the only segment @@ -161,6 +162,7 @@ export const formatVttPlaylist = ({ targetDuration: attributes.duration, timelineStarts: attributes.timelineStarts, discontinuityStarts, + serviceLocation: attributes.serviceLocation, discontinuitySequence, mediaSequence, segments diff --git a/test/inheritAttributes.test.js b/test/inheritAttributes.test.js index a489ef7c..dae013fe 100644 --- a/test/inheritAttributes.test.js +++ b/test/inheritAttributes.test.js @@ -927,10 +927,11 @@ QUnit.test('end to end - content steering - resolvable base URLs', function(asse id="test" width="720"> + /video - /video + /vtt @@ -957,7 +958,7 @@ QUnit.test('end to end - content steering - resolvable base URLs', function(asse attributes: { NOW, bandwidth: 5000000, - baseUrl: 'https://cdn1.example.com/', + baseUrl: 'https://cdn1.example.com/video', clientOffset: 0, codecs: 'avc1.64001e', height: 404, @@ -980,7 +981,7 @@ QUnit.test('end to end - content steering - resolvable base URLs', function(asse attributes: { NOW, bandwidth: 5000000, - baseUrl: 'https://cdn2.example.com/', + baseUrl: 'https://cdn2.example.com/video', clientOffset: 0, codecs: 'avc1.64001e', height: 404, @@ -1003,13 +1004,14 @@ QUnit.test('end to end - content steering - resolvable base URLs', function(asse attributes: { NOW, bandwidth: 256, - baseUrl: 'https://cdn1.example.com/video', + baseUrl: 'https://cdn1.example.com/vtt', clientOffset: 0, id: 'en', lang: 'en', mimeType: 'text/vtt', periodStart: 0, role: {}, + serviceLocation: 'alpha', sourceDuration: 0, type: 'dyanmic' }, @@ -1019,13 +1021,14 @@ QUnit.test('end to end - content steering - resolvable base URLs', function(asse attributes: { NOW, bandwidth: 256, - baseUrl: 'https://cdn2.example.com/video', + baseUrl: 'https://cdn2.example.com/vtt', clientOffset: 0, id: 'en', lang: 'en', mimeType: 'text/vtt', periodStart: 0, role: {}, + serviceLocation: 'beta', sourceDuration: 0, type: 'dyanmic' }, diff --git a/test/toM3u8.test.js b/test/toM3u8.test.js index 2440371e..29a231fa 100644 --- a/test/toM3u8.test.js +++ b/test/toM3u8.test.js @@ -213,6 +213,286 @@ QUnit.test('playlists', function(assert) { assert.deepEqual(toM3u8({ dashPlaylists }), expected); }); +QUnit.test('playlists with content steering', function(assert) { + const contentSteering = { + defaultServiceLocation: 'beta', + proxyServerURL: 'http://127.0.0.1:3455/steer', + queryBeforeStart: false, + serverURL: 'https://example.com/app/url' + }; + + const dashPlaylists = [ + { + attributes: { + bandwidth: 5000000, + baseUrl: 'https://cdn1.example.com/video', + clientOffset: 0, + codecs: 'avc1.64001e', + duration: 0, + height: 404, + id: 'test', + mimeType: 'video/mp4', + periodStart: 0, + role: { + value: 'main' + }, + serviceLocation: 'alpha', + sourceDuration: 0, + type: 'dyanmic', + width: 720 + }, + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn1.example.com/video', + uri: '', + serviceLocation: 'alpha' + }, + number: 1, + presentationTime: 0, + resolvedUri: 'https://cdn1.example.com/video', + serviceLocation: 'alpha', + timeline: 0, + uri: '' + } + ] + }, + { + attributes: { + bandwidth: 5000000, + baseUrl: 'https://cdn2.example.com/video', + clientOffset: 0, + codecs: 'avc1.64001e', + duration: 0, + height: 404, + id: 'test', + mimeType: 'video/mp4', + periodStart: 0, + role: { + value: 'main' + }, + serviceLocation: 'beta', + sourceDuration: 0, + type: 'dyanmic', + width: 720 + }, + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn2.example.com/video', + serviceLocation: 'beta', + uri: '' + }, + number: 1, + presentationTime: 0, + resolvedUri: 'https://cdn2.example.com/video', + serviceLocation: 'beta', + timeline: 0, + uri: '' + } + ] + }, + { + attributes: { + bandwidth: 256, + baseUrl: 'https://cdn1.example.com/vtt', + clientOffset: 0, + duration: 0, + id: 'en', + lang: 'en', + mimeType: 'text/vtt', + periodStart: 0, + role: {}, + serviceLocation: 'alpha', + sourceDuration: 0, + type: 'dyanmic' + }, + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn1.example.com/vtt', + serviceLocation: 'alpha', + uri: '' + }, + number: 1, + presentationTime: 0, + resolvedUri: 'https://cdn1.example.com/vtt', + serviceLocation: 'alpha', + timeline: 0, + uri: '' + } + ] + }, + { + attributes: { + bandwidth: 256, + baseUrl: 'https://cdn2.example.com/vtt', + clientOffset: 0, + id: 'en', + lang: 'en', + mimeType: 'text/vtt', + periodStart: 0, + role: {}, + serviceLocation: 'beta', + sourceDuration: 0, + type: 'dyanmic' + } + } + ]; + + const expected = { + allowCache: true, + contentSteering: { + defaultServiceLocation: 'beta', + proxyServerURL: 'http://127.0.0.1:3455/steer', + queryBeforeStart: false, + serverURL: 'https://example.com/app/url' + }, + discontinuityStarts: [], + duration: 0, + endList: true, + mediaGroups: { + AUDIO: {}, + ['CLOSED-CAPTIONS']: {}, + SUBTITLES: { + subs: { + en: { + autoselect: false, + default: false, + language: 'en', + playlists: [ + { + attributes: { + BANDWIDTH: 256, + NAME: 'en', + ['PROGRAM-ID']: 1 + }, + discontinuitySequence: 0, + discontinuityStarts: [], + endList: false, + mediaSequence: 0, + resolvedUri: 'https://cdn1.example.com/vtt', + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn1.example.com/vtt', + serviceLocation: 'alpha', + uri: '' + }, + number: 0, + presentationTime: 0, + resolvedUri: 'https://cdn1.example.com/vtt', + serviceLocation: 'alpha', + timeline: 0, + uri: '' + } + ], + serviceLocation: 'alpha', + targetDuration: 0, + timeline: 0, + timelineStarts: [ + { + start: 0, + timeline: 0 + }, + { + start: 0, + timeline: 0 + } + ], + uri: '' + } + ], + uri: '' + } + } + }, + VIDEO: {} + }, + playlists: [ + { + attributes: { + AUDIO: 'audio', + BANDWIDTH: 5000000, + CODECS: 'avc1.64001e', + NAME: 'test', + ['PROGRAM-ID']: 1, + RESOLUTION: { + height: 404, + width: 720 + }, + SUBTITLES: 'subs' + }, + discontinuitySequence: 0, + discontinuityStarts: [ + 1 + ], + endList: false, + mediaSequence: 0, + resolvedUri: '', + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn1.example.com/video', + serviceLocation: 'alpha', + uri: '' + }, + number: 0, + presentationTime: 0, + resolvedUri: 'https://cdn1.example.com/video', + serviceLocation: 'alpha', + timeline: 0, + uri: '' + }, + { + discontinuity: true, + duration: 0, + map: { + resolvedUri: 'https://cdn2.example.com/video', + serviceLocation: 'beta', + uri: '' + }, + number: 1, + presentationTime: 0, + resolvedUri: 'https://cdn2.example.com/video', + serviceLocation: 'beta', + timeline: 0, + uri: '' + } + ], + targetDuration: 0, + timeline: 0, + timelineStarts: [ + { + start: 0, + timeline: 0 + }, + { + start: 0, + timeline: 0 + } + ], + uri: '' + } + ], + segments: [], + timelineStarts: [ + { + start: 0, + timeline: 0 + } + ], + uri: '' + }; + + assert.deepEqual(toM3u8({ dashPlaylists, contentSteering }), expected); +}); + QUnit.test('playlists with content steering', function(assert) { const contentSteering = { defaultServiceLocation: 'beta', diff --git a/test/toPlaylists.test.js b/test/toPlaylists.test.js index fd0528ed..e29ff1f4 100644 --- a/test/toPlaylists.test.js +++ b/test/toPlaylists.test.js @@ -410,3 +410,210 @@ QUnit.test('presentationTime accounts for presentationTimeOffset', function(asse assert.deepEqual(toPlaylists(representations), playlists); }); + +QUnit.test('content steering', function(assert) { + const representations = [ + { + attributes: { + bandwidth: 5000000, + baseUrl: 'https://cdn1.example.com/video', + clientOffset: 0, + codecs: 'avc1.64001e', + height: 404, + id: 'test', + mimeType: 'video/mp4', + periodStart: 0, + role: { + value: 'main' + }, + serviceLocation: 'alpha', + sourceDuration: 0, + type: 'dyanmic', + width: 720 + }, + segmentInfo: { + template: {} + } + }, + { + attributes: { + bandwidth: 5000000, + baseUrl: 'https://cdn2.example.com/video', + clientOffset: 0, + codecs: 'avc1.64001e', + height: 404, + id: 'test', + mimeType: 'video/mp4', + periodStart: 0, + role: { + value: 'main' + }, + serviceLocation: 'beta', + sourceDuration: 0, + type: 'dyanmic', + width: 720 + }, + segmentInfo: { + template: {} + } + }, + { + attributes: { + bandwidth: 256, + baseUrl: 'https://cdn1.example.com/vtt', + clientOffset: 0, + id: 'en', + lang: 'en', + mimeType: 'text/vtt', + periodStart: 0, + role: {}, + serviceLocation: 'alpha', + sourceDuration: 0, + type: 'dyanmic' + }, + segmentInfo: { + template: {} + } + }, + { + attributes: { + bandwidth: 256, + baseUrl: 'https://cdn2.example.com/vtt', + clientOffset: 0, + id: 'en', + lang: 'en', + mimeType: 'text/vtt', + periodStart: 0, + role: {}, + serviceLocation: 'beta', + sourceDuration: 0, + type: 'dyanmic' + }, + segmentInfo: {} + } + ]; + + const playlists = [ + { + attributes: { + bandwidth: 5000000, + baseUrl: 'https://cdn1.example.com/video', + clientOffset: 0, + codecs: 'avc1.64001e', + duration: 0, + height: 404, + id: 'test', + mimeType: 'video/mp4', + periodStart: 0, + role: { + value: 'main' + }, + serviceLocation: 'alpha', + sourceDuration: 0, + type: 'dyanmic', + width: 720 + }, + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn1.example.com/video', + uri: '', + serviceLocation: 'alpha' + }, + number: 1, + presentationTime: 0, + resolvedUri: 'https://cdn1.example.com/video', + serviceLocation: 'alpha', + timeline: 0, + uri: '' + } + ] + }, + { + attributes: { + bandwidth: 5000000, + baseUrl: 'https://cdn2.example.com/video', + clientOffset: 0, + codecs: 'avc1.64001e', + duration: 0, + height: 404, + id: 'test', + mimeType: 'video/mp4', + periodStart: 0, + role: { + value: 'main' + }, + serviceLocation: 'beta', + sourceDuration: 0, + type: 'dyanmic', + width: 720 + }, + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn2.example.com/video', + serviceLocation: 'beta', + uri: '' + }, + number: 1, + presentationTime: 0, + resolvedUri: 'https://cdn2.example.com/video', + serviceLocation: 'beta', + timeline: 0, + uri: '' + } + ] + }, + { + attributes: { + bandwidth: 256, + baseUrl: 'https://cdn1.example.com/vtt', + clientOffset: 0, + duration: 0, + id: 'en', + lang: 'en', + mimeType: 'text/vtt', + periodStart: 0, + role: {}, + serviceLocation: 'alpha', + sourceDuration: 0, + type: 'dyanmic' + }, + segments: [ + { + duration: 0, + map: { + resolvedUri: 'https://cdn1.example.com/vtt', + serviceLocation: 'alpha', + uri: '' + }, + number: 1, + presentationTime: 0, + resolvedUri: 'https://cdn1.example.com/vtt', + serviceLocation: 'alpha', + timeline: 0, + uri: '' + } + ] + }, + { + attributes: { + bandwidth: 256, + baseUrl: 'https://cdn2.example.com/vtt', + clientOffset: 0, + id: 'en', + lang: 'en', + mimeType: 'text/vtt', + periodStart: 0, + role: {}, + serviceLocation: 'beta', + sourceDuration: 0, + type: 'dyanmic' + } + } + ]; + + assert.deepEqual(toPlaylists(representations), playlists); +}); From a77b9916da6168c10b7dfaba44a71258304bb82b Mon Sep 17 00:00:00 2001 From: wseymour15 Date: Tue, 22 Aug 2023 13:28:50 -0500 Subject: [PATCH 2/7] clean up to tests and minor functionality changes --- src/inheritAttributes.js | 4 ++-- src/segment/segmentTemplate.js | 5 ++++- src/segment/urlType.js | 7 +++++-- src/toM3u8.js | 15 ++++++++++++--- test/toM3u8.test.js | 2 +- test/toPlaylists.test.js | 6 +++++- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/inheritAttributes.js b/src/inheritAttributes.js index df6e4648..f6983a6e 100644 --- a/src/inheritAttributes.js +++ b/src/inheritAttributes.js @@ -40,8 +40,8 @@ export const buildBaseUrls = (references, baseUrlElements) => { // If the URL is resolved, we want to get the serviceLocation from the reference // assuming there is no serviceLocation on the initialBaseUrl - if (resolvedBaseUrl !== initialBaseUrl) { - finalBaseUrl.serviceLocation = finalBaseUrl.serviceLocation || reference.serviceLocation; + if (resolvedBaseUrl !== initialBaseUrl && !finalBaseUrl.serviceLocation && reference.serviceLocation) { + finalBaseUrl.serviceLocation = reference.serviceLocation; } return finalBaseUrl; diff --git a/src/segment/segmentTemplate.js b/src/segment/segmentTemplate.js index 1158fa4b..e8b92982 100644 --- a/src/segment/segmentTemplate.js +++ b/src/segment/segmentTemplate.js @@ -173,12 +173,15 @@ export const segmentsFromTemplate = (attributes, segmentTimeline) => { timeline: segment.timeline, duration: segment.duration, resolvedUri: resolveUrl(attributes.baseUrl || '', uri), - serviceLocation: attributes.serviceLocation, map: mapSegment, number: segment.number, presentationTime }; + if (attributes.serviceLocation) { + map.serviceLocation = attributes.serviceLocation; + } + return map; }); }; diff --git a/src/segment/urlType.js b/src/segment/urlType.js index dd3caaff..a1d87853 100644 --- a/src/segment/urlType.js +++ b/src/segment/urlType.js @@ -31,10 +31,13 @@ import window from 'global/window'; export const urlTypeToSegment = ({ baseUrl = '', source = '', range = '', serviceLocation = null, indexRange = '' }) => { const segment = { uri: source, - resolvedUri: resolveUrl(baseUrl || '', source), - serviceLocation + resolvedUri: resolveUrl(baseUrl || '', source) }; + if (serviceLocation) { + segment.serviceLocation = serviceLocation; + } + if (range || indexRange) { const rangeStr = range ? range : indexRange; const ranges = rangeStr.split('-'); diff --git a/src/toM3u8.js b/src/toM3u8.js index e6ed2630..682326b6 100644 --- a/src/toM3u8.js +++ b/src/toM3u8.js @@ -137,9 +137,13 @@ export const formatVttPlaylist = ({ timeline: attributes.periodStart, resolvedUri: attributes.baseUrl || '', duration: attributes.sourceDuration, - serviceLocation: attributes.serviceLocation, number: 0 }]; + + if (attributes.serviceLocation) { + segments[0].serviceLocation = attributes.serviceLocation; + } + // targetDuration should be the same duration as the only segment attributes.duration = attributes.sourceDuration; } @@ -153,7 +157,7 @@ export const formatVttPlaylist = ({ if (attributes.codecs) { m3u8Attributes.CODECS = attributes.codecs; } - return { + const vttPlaylist = { attributes: m3u8Attributes, uri: '', endList: attributes.type === 'static', @@ -162,11 +166,16 @@ export const formatVttPlaylist = ({ targetDuration: attributes.duration, timelineStarts: attributes.timelineStarts, discontinuityStarts, - serviceLocation: attributes.serviceLocation, discontinuitySequence, mediaSequence, segments }; + + if (attributes.serviceLocation) { + vttPlaylist.serviceLocation = attributes.serviceLocation; + } + + return vttPlaylist; }; export const organizeAudioPlaylists = (playlists, sidxMapping = {}, isAudioOnly = false) => { diff --git a/test/toM3u8.test.js b/test/toM3u8.test.js index 29a231fa..a32d29f1 100644 --- a/test/toM3u8.test.js +++ b/test/toM3u8.test.js @@ -213,7 +213,7 @@ QUnit.test('playlists', function(assert) { assert.deepEqual(toM3u8({ dashPlaylists }), expected); }); -QUnit.test('playlists with content steering', function(assert) { +QUnit.test('playlists with content steering and resolvable URLs', function(assert) { const contentSteering = { defaultServiceLocation: 'beta', proxyServerURL: 'http://127.0.0.1:3455/steer', diff --git a/test/toPlaylists.test.js b/test/toPlaylists.test.js index e29ff1f4..31760e42 100644 --- a/test/toPlaylists.test.js +++ b/test/toPlaylists.test.js @@ -187,11 +187,13 @@ QUnit.test('playlist with content steering BaseURLs', function(assert) { duration: 0, map: { resolvedUri: 'https://cdn1.example.com/', + serviceLocation: 'alpha', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/', + serviceLocation: 'alpha', timeline: 0, uri: '' } @@ -220,11 +222,13 @@ QUnit.test('playlist with content steering BaseURLs', function(assert) { duration: 0, map: { resolvedUri: 'https://cdn2.example.com/', + serviceLocation: 'beta', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn2.example.com/', + serviceLocation: 'beta', timeline: 0, uri: '' } @@ -411,7 +415,7 @@ QUnit.test('presentationTime accounts for presentationTimeOffset', function(asse assert.deepEqual(toPlaylists(representations), playlists); }); -QUnit.test('content steering', function(assert) { +QUnit.test('playlist with content steering and resolvable BaseURLs', function(assert) { const representations = [ { attributes: { From 6f111444853e8f14188621f84b46f041931de0e8 Mon Sep 17 00:00:00 2001 From: wseymour15 Date: Tue, 22 Aug 2023 13:59:17 -0500 Subject: [PATCH 3/7] remove unneeded sidx serviceLocation --- src/toM3u8.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/toM3u8.js b/src/toM3u8.js index 682326b6..b812ccd6 100644 --- a/src/toM3u8.js +++ b/src/toM3u8.js @@ -140,10 +140,6 @@ export const formatVttPlaylist = ({ number: 0 }]; - if (attributes.serviceLocation) { - segments[0].serviceLocation = attributes.serviceLocation; - } - // targetDuration should be the same duration as the only segment attributes.duration = attributes.sourceDuration; } From 5943c2968850da4871ee737bb7e3e95932112b43 Mon Sep 17 00:00:00 2001 From: wseymour15 Date: Thu, 24 Aug 2023 16:51:25 -0500 Subject: [PATCH 4/7] separate segments into playlists by baseURL --- src/toM3u8.js | 91 ++- ...multiperiod-startnumber-removed-periods.js | 24 +- test/manifests/multiperiod-startnumber.js | 612 +++++++++++------- test/toM3u8.test.js | 115 +++- 4 files changed, 562 insertions(+), 280 deletions(-) diff --git a/src/toM3u8.js b/src/toM3u8.js index b812ccd6..79b1e98f 100644 --- a/src/toM3u8.js +++ b/src/toM3u8.js @@ -11,45 +11,62 @@ export const generateSidxKey = (sidx) => sidx && sidx.uri + '-' + byteRangeToString(sidx.byterange); const mergeDiscontiguousPlaylists = playlists => { - const mergedPlaylists = values(playlists.reduce((acc, playlist) => { - // assuming playlist IDs are the same across periods - // TODO: handle multiperiod where representation sets are not the same - // across periods - const name = playlist.attributes.id + (playlist.attributes.lang || ''); - - if (!acc[name]) { - // First Period - acc[name] = playlist; - acc[name].attributes.timelineStarts = []; - } else { - // Subsequent Periods - if (playlist.segments) { - // first segment of subsequent periods signal a discontinuity - if (playlist.segments[0]) { - playlist.segments[0].discontinuity = true; + // Break out playlists into groups based on their baseUrl + const playlistsByBaseUrl = playlists.reduce(function(acc, cur) { + if (!acc[cur.attributes.baseUrl]) { + acc[cur.attributes.baseUrl] = []; + } + + acc[cur.attributes.baseUrl].push(cur); + + return acc; + }, {}); + + let allPlaylists = []; + + Object.values(playlistsByBaseUrl).forEach((playlistGroup) => { + const mergedPlaylists = values(playlistGroup.reduce((acc, playlist) => { + // assuming playlist IDs are the same across periods + // TODO: handle multiperiod where representation sets are not the same + // across periods + const name = playlist.attributes.id + (playlist.attributes.lang || ''); + + if (!acc[name]) { + // First Period + acc[name] = playlist; + acc[name].attributes.timelineStarts = []; + } else { + // Subsequent Periods + if (playlist.segments) { + // first segment of subsequent periods signal a discontinuity + if (playlist.segments[0]) { + playlist.segments[0].discontinuity = true; + } + acc[name].segments.push(...playlist.segments); } - acc[name].segments.push(...playlist.segments); - } - // bubble up contentProtection, this assumes all DRM content - // has the same contentProtection - if (playlist.attributes.contentProtection) { - acc[name].attributes.contentProtection = - playlist.attributes.contentProtection; + // bubble up contentProtection, this assumes all DRM content + // has the same contentProtection + if (playlist.attributes.contentProtection) { + acc[name].attributes.contentProtection = + playlist.attributes.contentProtection; + } } - } - acc[name].attributes.timelineStarts.push({ - // Although they represent the same number, it's important to have both to make it - // compatible with HLS potentially having a similar attribute. - start: playlist.attributes.periodStart, - timeline: playlist.attributes.periodStart - }); + acc[name].attributes.timelineStarts.push({ + // Although they represent the same number, it's important to have both to make it + // compatible with HLS potentially having a similar attribute. + start: playlist.attributes.periodStart, + timeline: playlist.attributes.periodStart + }); - return acc; - }, {})); + return acc; + }, {})); + + allPlaylists = allPlaylists.concat(mergedPlaylists); + }); - return mergedPlaylists.map(playlist => { + return allPlaylists.map(playlist => { playlist.discontinuityStarts = findIndexes(playlist.segments || [], 'discontinuity'); @@ -111,6 +128,10 @@ export const formatAudioPlaylist = ({ playlist.contentProtection = attributes.contentProtection; } + if (attributes.serviceLocation) { + playlist.serviceLocation = attributes.serviceLocation; + } + if (sidx) { playlist.sidx = sidx; } @@ -311,6 +332,10 @@ export const formatVideoPlaylist = ({ playlist.contentProtection = attributes.contentProtection; } + if (attributes.serviceLocation) { + playlist.serviceLocation = attributes.serviceLocation; + } + if (sidx) { playlist.sidx = sidx; } diff --git a/test/manifests/multiperiod-startnumber-removed-periods.js b/test/manifests/multiperiod-startnumber-removed-periods.js index e81f653f..6c444b47 100644 --- a/test/manifests/multiperiod-startnumber-removed-periods.js +++ b/test/manifests/multiperiod-startnumber-removed-periods.js @@ -25,7 +25,7 @@ export const parsedManifest = { 'PROGRAM-ID': 1 }, endList: false, - mediaSequence: 7, + mediaSequence: 3, discontinuitySequence: 2, discontinuityStarts: [0], timelineStarts: [ @@ -41,7 +41,7 @@ export const parsedManifest = { uri: 'init.mp4' }, presentationTime: 111, - number: 7, + number: 3, resolvedUri: 'http://example.com/audio/v0/862.m4f', timeline: 111, uri: '862.m4f' @@ -53,7 +53,7 @@ export const parsedManifest = { uri: 'init.mp4' }, presentationTime: 112, - number: 8, + number: 4, resolvedUri: 'http://example.com/audio/v0/863.m4f', timeline: 111, uri: '863.m4f' @@ -65,7 +65,7 @@ export const parsedManifest = { uri: 'init.mp4' }, presentationTime: 113, - number: 9, + number: 5, resolvedUri: 'http://example.com/audio/v0/864.m4f', timeline: 111, uri: '864.m4f' @@ -231,7 +231,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: false, - mediaSequence: 7, + mediaSequence: 3, discontinuitySequence: 2, timelineStarts: [ { start: 111, timeline: 111} @@ -247,7 +247,7 @@ export const parsedManifest = { uri: 'F_init.mp4' }, presentationTime: 111, - number: 7, + number: 3, resolvedUri: 'http://example.com/video/F/F862.m4f', timeline: 111, uri: 'F862.m4f' @@ -259,7 +259,7 @@ export const parsedManifest = { uri: 'F_init.mp4' }, presentationTime: 112, - number: 8, + number: 4, resolvedUri: 'http://example.com/video/F/F863.m4f', timeline: 111, uri: 'F863.m4f' @@ -271,7 +271,7 @@ export const parsedManifest = { uri: 'F_init.mp4' }, presentationTime: 113, - number: 9, + number: 5, resolvedUri: 'http://example.com/video/F/F864.m4f', timeline: 111, uri: 'F864.m4f' @@ -426,7 +426,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: false, - mediaSequence: 7, + mediaSequence: 3, discontinuitySequence: 2, timelineStarts: [ { start: 111, timeline: 111} @@ -442,7 +442,7 @@ export const parsedManifest = { uri: 'C_init.mp4' }, presentationTime: 111, - number: 7, + number: 3, resolvedUri: 'http://example.com/video/C/C862.m4f', timeline: 111, uri: 'C862.m4f' @@ -454,7 +454,7 @@ export const parsedManifest = { uri: 'C_init.mp4' }, presentationTime: 112, - number: 8, + number: 4, resolvedUri: 'http://example.com/video/C/C863.m4f', timeline: 111, uri: 'C863.m4f' @@ -466,7 +466,7 @@ export const parsedManifest = { uri: 'C_init.mp4' }, presentationTime: 113, - number: 9, + number: 5, resolvedUri: 'http://example.com/video/C/C864.m4f', timeline: 111, uri: 'C864.m4f' diff --git a/test/manifests/multiperiod-startnumber.js b/test/manifests/multiperiod-startnumber.js index a7adeacb..6bf69b19 100644 --- a/test/manifests/multiperiod-startnumber.js +++ b/test/manifests/multiperiod-startnumber.js @@ -24,16 +24,10 @@ export const parsedManifest = { 'NAME': 'v0', 'PROGRAM-ID': 1 }, + discontinuitySequence: 0, + discontinuityStarts: [], endList: false, mediaSequence: 0, - discontinuitySequence: 0, - discontinuityStarts: [3, 5, 7], - timelineStarts: [ - { start: 100, timeline: 100}, - { start: 103, timeline: 103}, - { start: 107, timeline: 107}, - { start: 111, timeline: 111} - ], resolvedUri: '', segments: [ { @@ -71,16 +65,42 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/502.m4f', timeline: 100, uri: '502.m4f' - }, + } + ], + targetDuration: 1, + timeline: 100, + timelineStarts: [ + { + start: 100, + timeline: 100 + } + ], + uri: '' + }, + { + attributes: { + 'BANDWIDTH': 128352, + 'CODECS': 'mp4a.40.5', + 'NAME': 'v0', + 'PROGRAM-ID': 1 + }, + discontinuitySequence: 1, + discontinuityStarts: [ + 2, + 4 + ], + endList: false, + mediaSequence: 0, + resolvedUri: '', + segments: [ { - discontinuity: true, duration: 2, map: { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, + number: 0, presentationTime: 103, - number: 3, resolvedUri: 'http://example.com/audio/v0/000.m4f', timeline: 103, uri: '000.m4f' @@ -91,8 +111,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, + number: 1, presentationTime: 105, - number: 4, resolvedUri: 'http://example.com/audio/v0/001.m4f', timeline: 103, uri: '001.m4f' @@ -104,8 +124,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, + number: 2, presentationTime: 107, - number: 5, resolvedUri: 'http://example.com/audio/v0/000.m4f', timeline: 107, uri: '000.m4f' @@ -116,8 +136,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, + number: 3, presentationTime: 109, - number: 6, resolvedUri: 'http://example.com/audio/v0/001.m4f', timeline: 107, uri: '001.m4f' @@ -129,8 +149,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, + number: 4, presentationTime: 111, - number: 7, resolvedUri: 'http://example.com/audio/v0/862.m4f', timeline: 111, uri: '862.m4f' @@ -141,8 +161,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, + number: 5, presentationTime: 112, - number: 8, resolvedUri: 'http://example.com/audio/v0/863.m4f', timeline: 111, uri: '863.m4f' @@ -153,15 +173,29 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, + number: 6, presentationTime: 113, - number: 9, resolvedUri: 'http://example.com/audio/v0/864.m4f', timeline: 111, uri: '864.m4f' } ], - targetDuration: 1, - timeline: 100, + targetDuration: 2, + timeline: 103, + timelineStarts: [ + { + start: 103, + timeline: 103 + }, + { + start: 107, + timeline: 107 + }, + { + start: 111, + timeline: 111 + } + ], uri: '' } ], @@ -189,16 +223,14 @@ export const parsedManifest = { }, 'SUBTITLES': 'subs' }, - endList: false, - mediaSequence: 0, discontinuitySequence: 0, - discontinuityStarts: [3, 5, 7], - timelineStarts: [ - { start: 100, timeline: 100}, - { start: 103, timeline: 103}, - { start: 107, timeline: 107}, - { start: 111, timeline: 111} + discontinuityStarts: [ + 3, + 5, + 7 ], + endList: false, + mediaSequence: 0, resolvedUri: '', segments: [ { @@ -207,8 +239,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 100, number: 0, + presentationTime: 100, resolvedUri: 'http://example.com/video/D/D500.m4f', timeline: 100, uri: 'D500.m4f' @@ -219,8 +251,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 101, number: 1, + presentationTime: 101, resolvedUri: 'http://example.com/video/D/D501.m4f', timeline: 100, uri: 'D501.m4f' @@ -231,8 +263,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 102, number: 2, + presentationTime: 102, resolvedUri: 'http://example.com/video/D/D502.m4f', timeline: 100, uri: 'D502.m4f' @@ -244,8 +276,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 103, number: 3, + presentationTime: 103, resolvedUri: 'http://example.com/video/D/D000.m4f', timeline: 103, uri: 'D000.m4f' @@ -256,8 +288,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 105, number: 4, + presentationTime: 105, resolvedUri: 'http://example.com/video/D/D001.m4f', timeline: 103, uri: 'D001.m4f' @@ -269,8 +301,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 107, number: 5, + presentationTime: 107, resolvedUri: 'http://example.com/video/D/D000.m4f', timeline: 107, uri: 'D000.m4f' @@ -281,8 +313,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 109, number: 6, + presentationTime: 109, resolvedUri: 'http://example.com/video/D/D001.m4f', timeline: 107, uri: 'D001.m4f' @@ -294,8 +326,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 111, number: 7, + presentationTime: 111, resolvedUri: 'http://example.com/video/D/D862.m4f', timeline: 111, uri: 'D862.m4f' @@ -306,8 +338,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 112, number: 8, + presentationTime: 112, resolvedUri: 'http://example.com/video/D/D863.m4f', timeline: 111, uri: 'D863.m4f' @@ -318,8 +350,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - presentationTime: 113, number: 9, + presentationTime: 113, resolvedUri: 'http://example.com/video/D/D864.m4f', timeline: 111, uri: 'D864.m4f' @@ -327,6 +359,24 @@ export const parsedManifest = { ], targetDuration: 1, timeline: 100, + timelineStarts: [ + { + start: 100, + timeline: 100 + }, + { + start: 103, + timeline: 103 + }, + { + start: 107, + timeline: 107 + }, + { + start: 111, + timeline: 111 + } + ], uri: '' }, { @@ -343,16 +393,14 @@ export const parsedManifest = { }, 'SUBTITLES': 'subs' }, - endList: false, - mediaSequence: 0, discontinuitySequence: 0, - discontinuityStarts: [3, 5, 7], - timelineStarts: [ - { start: 100, timeline: 100}, - { start: 103, timeline: 103}, - { start: 107, timeline: 107}, - { start: 111, timeline: 111} + discontinuityStarts: [ + 3, + 5, + 7 ], + endList: false, + mediaSequence: 0, resolvedUri: '', segments: [ { @@ -361,8 +409,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 100, number: 0, + presentationTime: 100, resolvedUri: 'http://example.com/video/E/E500.m4f', timeline: 100, uri: 'E500.m4f' @@ -373,8 +421,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 101, number: 1, + presentationTime: 101, resolvedUri: 'http://example.com/video/E/E501.m4f', timeline: 100, uri: 'E501.m4f' @@ -385,8 +433,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 102, number: 2, + presentationTime: 102, resolvedUri: 'http://example.com/video/E/E502.m4f', timeline: 100, uri: 'E502.m4f' @@ -398,8 +446,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 103, number: 3, + presentationTime: 103, resolvedUri: 'http://example.com/video/E/E000.m4f', timeline: 103, uri: 'E000.m4f' @@ -410,8 +458,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 105, number: 4, + presentationTime: 105, resolvedUri: 'http://example.com/video/E/E001.m4f', timeline: 103, uri: 'E001.m4f' @@ -423,8 +471,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 107, number: 5, + presentationTime: 107, resolvedUri: 'http://example.com/video/E/E000.m4f', timeline: 107, uri: 'E000.m4f' @@ -435,8 +483,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 109, number: 6, + presentationTime: 109, resolvedUri: 'http://example.com/video/E/E001.m4f', timeline: 107, uri: 'E001.m4f' @@ -448,8 +496,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 111, number: 7, + presentationTime: 111, resolvedUri: 'http://example.com/video/E/E862.m4f', timeline: 111, uri: 'E862.m4f' @@ -460,8 +508,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 112, number: 8, + presentationTime: 112, resolvedUri: 'http://example.com/video/E/E863.m4f', timeline: 111, uri: 'E863.m4f' @@ -472,8 +520,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - presentationTime: 113, number: 9, + presentationTime: 113, resolvedUri: 'http://example.com/video/E/E864.m4f', timeline: 111, uri: 'E864.m4f' @@ -481,6 +529,24 @@ export const parsedManifest = { ], targetDuration: 1, timeline: 100, + timelineStarts: [ + { + start: 100, + timeline: 100 + }, + { + start: 103, + timeline: 103 + }, + { + start: 107, + timeline: 107 + }, + { + start: 111, + timeline: 111 + } + ], uri: '' }, { @@ -497,16 +563,10 @@ export const parsedManifest = { }, 'SUBTITLES': 'subs' }, + discontinuitySequence: 0, + discontinuityStarts: [], endList: false, mediaSequence: 0, - discontinuitySequence: 0, - discontinuityStarts: [3, 5, 7], - timelineStarts: [ - { start: 100, timeline: 100}, - { start: 103, timeline: 103}, - { start: 107, timeline: 107}, - { start: 111, timeline: 111} - ], resolvedUri: '', segments: [ { @@ -515,8 +575,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/F_init.mp4', uri: 'F_init.mp4' }, - presentationTime: 100, number: 0, + presentationTime: 100, resolvedUri: 'http://example.com/video/E/F500.m4f', timeline: 100, uri: 'F500.m4f' @@ -527,8 +587,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/F_init.mp4', uri: 'F_init.mp4' }, - presentationTime: 101, number: 1, + presentationTime: 101, resolvedUri: 'http://example.com/video/E/F501.m4f', timeline: 100, uri: 'F501.m4f' @@ -539,102 +599,88 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/F_init.mp4', uri: 'F_init.mp4' }, - presentationTime: 102, number: 2, + presentationTime: 102, resolvedUri: 'http://example.com/video/E/F502.m4f', timeline: 100, uri: 'F502.m4f' - }, - { - discontinuity: true, - duration: 2, - map: { - resolvedUri: 'http://example.com/video/F/F_init.mp4', - uri: 'F_init.mp4' - }, - presentationTime: 103, - number: 3, - resolvedUri: 'http://example.com/video/F/F000.m4f', - timeline: 103, - uri: 'F000.m4f' - }, - { - duration: 2, - map: { - resolvedUri: 'http://example.com/video/F/F_init.mp4', - uri: 'F_init.mp4' - }, - presentationTime: 105, - number: 4, - resolvedUri: 'http://example.com/video/F/F001.m4f', - timeline: 103, - uri: 'F001.m4f' - }, - { - discontinuity: true, - duration: 1, - map: { - resolvedUri: 'http://example.com/video/F/F_init.mp4', - uri: 'F_init.mp4' - }, - presentationTime: 107, - number: 5, - resolvedUri: 'http://example.com/video/F/F000.m4f', - timeline: 107, - uri: 'F000.m4f' - }, + } + ], + targetDuration: 1, + timeline: 100, + timelineStarts: [ { - duration: 1, - map: { - resolvedUri: 'http://example.com/video/F/F_init.mp4', - uri: 'F_init.mp4' - }, - presentationTime: 108, - number: 6, - resolvedUri: 'http://example.com/video/F/F001.m4f', - timeline: 107, - uri: 'F001.m4f' + start: 100, + timeline: 100 + } + ], + uri: '' + }, + { + attributes: { + 'AUDIO': 'audio', + 'BANDWIDTH': 1277155, + 'CODECS': 'avc1.4d001e', + 'FRAME-RATE': 30, + 'NAME': 'C', + 'PROGRAM-ID': 1, + 'RESOLUTION': { + height: 540, + width: 960 }, + 'SUBTITLES': 'subs' + }, + discontinuitySequence: 0, + discontinuityStarts: [], + endList: false, + mediaSequence: 0, + resolvedUri: '', + segments: [ { - discontinuity: true, duration: 1, map: { - resolvedUri: 'http://example.com/video/F/F_init.mp4', - uri: 'F_init.mp4' + resolvedUri: 'http://example.com/video/E/C_init.mp4', + uri: 'C_init.mp4' }, - presentationTime: 111, - number: 7, - resolvedUri: 'http://example.com/video/F/F862.m4f', - timeline: 111, - uri: 'F862.m4f' + number: 0, + presentationTime: 100, + resolvedUri: 'http://example.com/video/E/C500.m4f', + timeline: 100, + uri: 'C500.m4f' }, { duration: 1, map: { - resolvedUri: 'http://example.com/video/F/F_init.mp4', - uri: 'F_init.mp4' + resolvedUri: 'http://example.com/video/E/C_init.mp4', + uri: 'C_init.mp4' }, - presentationTime: 112, - number: 8, - resolvedUri: 'http://example.com/video/F/F863.m4f', - timeline: 111, - uri: 'F863.m4f' + number: 1, + presentationTime: 101, + resolvedUri: 'http://example.com/video/E/C501.m4f', + timeline: 100, + uri: 'C501.m4f' }, { duration: 1, map: { - resolvedUri: 'http://example.com/video/F/F_init.mp4', - uri: 'F_init.mp4' + resolvedUri: 'http://example.com/video/E/C_init.mp4', + uri: 'C_init.mp4' }, - presentationTime: 113, - number: 9, - resolvedUri: 'http://example.com/video/F/F864.m4f', - timeline: 111, - uri: 'F864.m4f' + number: 2, + presentationTime: 102, + resolvedUri: 'http://example.com/video/E/C502.m4f', + timeline: 100, + uri: 'C502.m4f' } ], targetDuration: 1, timeline: 100, + timelineStarts: [ + { + start: 100, + timeline: 100 + } + ], uri: '' }, { @@ -651,16 +697,14 @@ export const parsedManifest = { }, 'SUBTITLES': 'subs' }, - endList: false, - mediaSequence: 0, discontinuitySequence: 0, - discontinuityStarts: [3, 5, 7], - timelineStarts: [ - { start: 100, timeline: 100}, - { start: 103, timeline: 103}, - { start: 107, timeline: 107}, - { start: 111, timeline: 111} + discontinuityStarts: [ + 3, + 5, + 7 ], + endList: false, + mediaSequence: 0, resolvedUri: '', segments: [ { @@ -669,8 +713,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 100, number: 0, + presentationTime: 100, resolvedUri: 'http://example.com/video/A/A500.m4f', timeline: 100, uri: 'A500.m4f' @@ -681,8 +725,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 101, number: 1, + presentationTime: 101, resolvedUri: 'http://example.com/video/A/A501.m4f', timeline: 100, uri: 'A501.m4f' @@ -693,8 +737,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 102, number: 2, + presentationTime: 102, resolvedUri: 'http://example.com/video/A/A502.m4f', timeline: 100, uri: 'A502.m4f' @@ -706,8 +750,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 103, number: 3, + presentationTime: 103, resolvedUri: 'http://example.com/video/A/A000.m4f', timeline: 103, uri: 'A000.m4f' @@ -718,8 +762,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 105, number: 4, + presentationTime: 105, resolvedUri: 'http://example.com/video/A/A001.m4f', timeline: 103, uri: 'A001.m4f' @@ -731,8 +775,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 107, number: 5, + presentationTime: 107, resolvedUri: 'http://example.com/video/A/A000.m4f', timeline: 107, uri: 'A000.m4f' @@ -743,8 +787,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 109, number: 6, + presentationTime: 109, resolvedUri: 'http://example.com/video/A/A001.m4f', timeline: 107, uri: 'A001.m4f' @@ -756,8 +800,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 111, number: 7, + presentationTime: 111, resolvedUri: 'http://example.com/video/A/A862.m4f', timeline: 111, uri: 'A862.m4f' @@ -768,8 +812,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 112, number: 8, + presentationTime: 112, resolvedUri: 'http://example.com/video/A/A863.m4f', timeline: 111, uri: 'A863.m4f' @@ -780,8 +824,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - presentationTime: 113, number: 9, + presentationTime: 113, resolvedUri: 'http://example.com/video/A/A864.m4f', timeline: 111, uri: 'A864.m4f' @@ -789,6 +833,24 @@ export const parsedManifest = { ], targetDuration: 1, timeline: 100, + timelineStarts: [ + { + start: 100, + timeline: 100 + }, + { + start: 103, + timeline: 103 + }, + { + start: 107, + timeline: 107 + }, + { + start: 111, + timeline: 111 + } + ], uri: '' }, { @@ -805,16 +867,14 @@ export const parsedManifest = { }, 'SUBTITLES': 'subs' }, - endList: false, - mediaSequence: 0, discontinuitySequence: 0, - discontinuityStarts: [3, 5, 7], - timelineStarts: [ - { start: 100, timeline: 100}, - { start: 103, timeline: 103}, - { start: 107, timeline: 107}, - { start: 111, timeline: 111} + discontinuityStarts: [ + 3, + 5, + 7 ], + endList: false, + mediaSequence: 0, resolvedUri: '', segments: [ { @@ -823,8 +883,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 100, number: 0, + presentationTime: 100, resolvedUri: 'http://example.com/video/B/B500.m4f', timeline: 100, uri: 'B500.m4f' @@ -835,8 +895,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 101, number: 1, + presentationTime: 101, resolvedUri: 'http://example.com/video/B/B501.m4f', timeline: 100, uri: 'B501.m4f' @@ -847,8 +907,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 102, number: 2, + presentationTime: 102, resolvedUri: 'http://example.com/video/B/B502.m4f', timeline: 100, uri: 'B502.m4f' @@ -860,8 +920,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 103, number: 3, + presentationTime: 103, resolvedUri: 'http://example.com/video/B/B000.m4f', timeline: 103, uri: 'B000.m4f' @@ -872,8 +932,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 105, number: 4, + presentationTime: 105, resolvedUri: 'http://example.com/video/B/B001.m4f', timeline: 103, uri: 'B001.m4f' @@ -885,8 +945,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 107, number: 5, + presentationTime: 107, resolvedUri: 'http://example.com/video/B/B000.m4f', timeline: 107, uri: 'B000.m4f' @@ -897,8 +957,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 109, number: 6, + presentationTime: 109, resolvedUri: 'http://example.com/video/B/B001.m4f', timeline: 107, uri: 'B001.m4f' @@ -910,8 +970,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 111, number: 7, + presentationTime: 111, resolvedUri: 'http://example.com/video/B/B862.m4f', timeline: 111, uri: 'B862.m4f' @@ -922,8 +982,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 112, number: 8, + presentationTime: 112, resolvedUri: 'http://example.com/video/B/B863.m4f', timeline: 111, uri: 'B863.m4f' @@ -934,8 +994,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - presentationTime: 113, number: 9, + presentationTime: 113, resolvedUri: 'http://example.com/video/B/B864.m4f', timeline: 111, uri: 'B864.m4f' @@ -943,79 +1003,185 @@ export const parsedManifest = { ], targetDuration: 1, timeline: 100, + timelineStarts: [ + { + start: 100, + timeline: 100 + }, + { + start: 103, + timeline: 103 + }, + { + start: 107, + timeline: 107 + }, + { + start: 111, + timeline: 111 + } + ], uri: '' }, { attributes: { 'AUDIO': 'audio', - 'BANDWIDTH': 1277155, - 'CODECS': 'avc1.4d001e', - 'FRAME-RATE': 30, - 'NAME': 'C', + 'BANDWIDTH': 2215557, + 'CODECS': 'avc1.640020', + 'FRAME-RATE': 60, + 'NAME': 'F', 'PROGRAM-ID': 1, 'RESOLUTION': { - height: 540, - width: 960 + height: 720, + width: 1280 }, 'SUBTITLES': 'subs' }, + discontinuitySequence: 1, + discontinuityStarts: [ + 2, + 4 + ], endList: false, mediaSequence: 0, - discontinuitySequence: 0, - discontinuityStarts: [3, 5, 7], - timelineStarts: [ - { start: 100, timeline: 100}, - { start: 103, timeline: 103}, - { start: 107, timeline: 107}, - { start: 111, timeline: 111} - ], resolvedUri: '', segments: [ { - duration: 1, + duration: 2, map: { - resolvedUri: 'http://example.com/video/E/C_init.mp4', - uri: 'C_init.mp4' + resolvedUri: 'http://example.com/video/F/F_init.mp4', + uri: 'F_init.mp4' }, - presentationTime: 100, number: 0, - resolvedUri: 'http://example.com/video/E/C500.m4f', - timeline: 100, - uri: 'C500.m4f' + presentationTime: 103, + resolvedUri: 'http://example.com/video/F/F000.m4f', + timeline: 103, + uri: 'F000.m4f' }, { - duration: 1, + duration: 2, map: { - resolvedUri: 'http://example.com/video/E/C_init.mp4', - uri: 'C_init.mp4' + resolvedUri: 'http://example.com/video/F/F_init.mp4', + uri: 'F_init.mp4' }, - presentationTime: 101, number: 1, - resolvedUri: 'http://example.com/video/E/C501.m4f', - timeline: 100, - uri: 'C501.m4f' + presentationTime: 105, + resolvedUri: 'http://example.com/video/F/F001.m4f', + timeline: 103, + uri: 'F001.m4f' }, { + discontinuity: true, duration: 1, map: { - resolvedUri: 'http://example.com/video/E/C_init.mp4', - uri: 'C_init.mp4' + resolvedUri: 'http://example.com/video/F/F_init.mp4', + uri: 'F_init.mp4' }, - presentationTime: 102, number: 2, - resolvedUri: 'http://example.com/video/E/C502.m4f', - timeline: 100, - uri: 'C502.m4f' + presentationTime: 107, + resolvedUri: 'http://example.com/video/F/F000.m4f', + timeline: 107, + uri: 'F000.m4f' + }, + { + duration: 1, + map: { + resolvedUri: 'http://example.com/video/F/F_init.mp4', + uri: 'F_init.mp4' + }, + number: 3, + presentationTime: 108, + resolvedUri: 'http://example.com/video/F/F001.m4f', + timeline: 107, + uri: 'F001.m4f' }, { discontinuity: true, + duration: 1, + map: { + resolvedUri: 'http://example.com/video/F/F_init.mp4', + uri: 'F_init.mp4' + }, + number: 4, + presentationTime: 111, + resolvedUri: 'http://example.com/video/F/F862.m4f', + timeline: 111, + uri: 'F862.m4f' + }, + { + duration: 1, + map: { + resolvedUri: 'http://example.com/video/F/F_init.mp4', + uri: 'F_init.mp4' + }, + number: 5, + presentationTime: 112, + resolvedUri: 'http://example.com/video/F/F863.m4f', + timeline: 111, + uri: 'F863.m4f' + }, + { + duration: 1, + map: { + resolvedUri: 'http://example.com/video/F/F_init.mp4', + uri: 'F_init.mp4' + }, + number: 6, + presentationTime: 113, + resolvedUri: 'http://example.com/video/F/F864.m4f', + timeline: 111, + uri: 'F864.m4f' + } + ], + targetDuration: 2, + timeline: 103, + timelineStarts: [ + { + start: 103, + timeline: 103 + }, + { + start: 107, + timeline: 107 + }, + { + start: 111, + timeline: 111 + } + ], + uri: '' + }, + { + attributes: { + 'AUDIO': 'audio', + 'BANDWIDTH': 1048480, + 'CODECS': 'avc1.4d001f', + 'FRAME-RATE': 30, + 'NAME': 'C', + 'PROGRAM-ID': 1, + 'RESOLUTION': { + height: 540, + width: 960 + }, + 'SUBTITLES': 'subs' + }, + discontinuitySequence: 1, + discontinuityStarts: [ + 2, + 4 + ], + endList: false, + mediaSequence: 0, + resolvedUri: '', + segments: [ + { duration: 2, map: { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, + number: 0, presentationTime: 103, - number: 3, resolvedUri: 'http://example.com/video/C/C000.m4f', timeline: 103, uri: 'C000.m4f' @@ -1026,8 +1192,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, + number: 1, presentationTime: 105, - number: 4, resolvedUri: 'http://example.com/video/C/C001.m4f', timeline: 103, uri: 'C001.m4f' @@ -1039,8 +1205,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, + number: 2, presentationTime: 107, - number: 5, resolvedUri: 'http://example.com/video/C/C000.m4f', timeline: 107, uri: 'C000.m4f' @@ -1051,8 +1217,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, + number: 3, presentationTime: 109, - number: 6, resolvedUri: 'http://example.com/video/C/C001.m4f', timeline: 107, uri: 'C001.m4f' @@ -1064,8 +1230,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, + number: 4, presentationTime: 111, - number: 7, resolvedUri: 'http://example.com/video/C/C862.m4f', timeline: 111, uri: 'C862.m4f' @@ -1076,8 +1242,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, + number: 5, presentationTime: 112, - number: 8, resolvedUri: 'http://example.com/video/C/C863.m4f', timeline: 111, uri: 'C863.m4f' @@ -1088,15 +1254,29 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, + number: 6, presentationTime: 113, - number: 9, resolvedUri: 'http://example.com/video/C/C864.m4f', timeline: 111, uri: 'C864.m4f' } ], - targetDuration: 1, - timeline: 100, + targetDuration: 2, + timeline: 103, + timelineStarts: [ + { + start: 103, + timeline: 103 + }, + { + start: 107, + timeline: 107 + }, + { + start: 111, + timeline: 111 + } + ], uri: '' } ], diff --git a/test/toM3u8.test.js b/test/toM3u8.test.js index a32d29f1..e527d097 100644 --- a/test/toM3u8.test.js +++ b/test/toM3u8.test.js @@ -398,7 +398,34 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser { start: 0, timeline: 0 - }, + } + ], + uri: '' + }, + { + attributes: { + BANDWIDTH: 256, + NAME: 'en', + ['PROGRAM-ID']: 1 + }, + discontinuitySequence: 0, + discontinuityStarts: [], + endList: false, + mediaSequence: 0, + resolvedUri: 'https://cdn2.example.com/vtt', + segments: [ + { + duration: 0, + number: 0, + resolvedUri: 'https://cdn2.example.com/vtt', + timeline: 0, + uri: 'https://cdn2.example.com/vtt' + } + ], + serviceLocation: 'beta', + targetDuration: 0, + timeline: 0, + timelineStarts: [ { start: 0, timeline: 0 @@ -428,9 +455,7 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser SUBTITLES: 'subs' }, discontinuitySequence: 0, - discontinuityStarts: [ - 1 - ], + discontinuityStarts: [], endList: false, mediaSequence: 0, resolvedUri: '', @@ -448,16 +473,46 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser serviceLocation: 'alpha', timeline: 0, uri: '' + } + ], + serviceLocation: 'alpha', + targetDuration: 0, + timeline: 0, + timelineStarts: [ + { + start: 0, + timeline: 0 + } + ], + uri: '' + }, + { + attributes: { + AUDIO: 'audio', + BANDWIDTH: 5000000, + CODECS: 'avc1.64001e', + NAME: 'test', + ['PROGRAM-ID']: 1, + RESOLUTION: { + height: 404, + width: 720 }, + SUBTITLES: 'subs' + }, + discontinuitySequence: 0, + discontinuityStarts: [], + endList: false, + mediaSequence: 0, + resolvedUri: '', + segments: [ { - discontinuity: true, duration: 0, map: { resolvedUri: 'https://cdn2.example.com/video', serviceLocation: 'beta', uri: '' }, - number: 1, + number: 0, presentationTime: 0, resolvedUri: 'https://cdn2.example.com/video', serviceLocation: 'beta', @@ -465,13 +520,10 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser uri: '' } ], + serviceLocation: 'beta', targetDuration: 0, timeline: 0, timelineStarts: [ - { - start: 0, - timeline: 0 - }, { start: 0, timeline: 0 @@ -672,9 +724,7 @@ QUnit.test('playlists with content steering', function(assert) { SUBTITLES: 'subs' }, discontinuitySequence: 0, - discontinuityStarts: [ - 1 - ], + discontinuityStarts: [], endList: false, mediaSequence: 0, resolvedUri: '', @@ -690,28 +740,55 @@ QUnit.test('playlists with content steering', function(assert) { resolvedUri: 'https://cdn1.example.com/', timeline: 0, uri: '' + } + ], + serviceLocation: 'alpha', + targetDuration: 0, + timeline: 0, + timelineStarts: [ + { + start: 0, + timeline: 0 + } + ], + uri: '' + }, + { + attributes: { + AUDIO: 'audio', + BANDWIDTH: 5000000, + CODECS: 'avc1.64001e', + NAME: 'test', + ['PROGRAM-ID']: 1, + RESOLUTION: { + height: 404, + width: 720 }, + SUBTITLES: 'subs' + }, + discontinuitySequence: 0, + discontinuityStarts: [], + endList: false, + mediaSequence: 0, + resolvedUri: '', + segments: [ { - discontinuity: true, duration: 0, map: { resolvedUri: 'https://cdn2.example.com/', uri: '' }, - number: 1, + number: 0, presentationTime: 0, resolvedUri: 'https://cdn2.example.com/', timeline: 0, uri: '' } ], + serviceLocation: 'beta', targetDuration: 0, timeline: 0, timelineStarts: [ - { - start: 0, - timeline: 0 - }, { start: 0, timeline: 0 From e7c75631d94ecc6ba1f9829d40c7005d5292cbb0 Mon Sep 17 00:00:00 2001 From: wseymour15 Date: Fri, 25 Aug 2023 10:21:33 -0500 Subject: [PATCH 5/7] format test file better --- test/manifests/multiperiod-startnumber.js | 317 +++++++--------------- 1 file changed, 104 insertions(+), 213 deletions(-) diff --git a/test/manifests/multiperiod-startnumber.js b/test/manifests/multiperiod-startnumber.js index 6bf69b19..1da9d25a 100644 --- a/test/manifests/multiperiod-startnumber.js +++ b/test/manifests/multiperiod-startnumber.js @@ -24,10 +24,10 @@ export const parsedManifest = { 'NAME': 'v0', 'PROGRAM-ID': 1 }, - discontinuitySequence: 0, - discontinuityStarts: [], endList: false, mediaSequence: 0, + discontinuitySequence: 0, + discontinuityStarts: [], resolvedUri: '', segments: [ { @@ -70,10 +70,7 @@ export const parsedManifest = { targetDuration: 1, timeline: 100, timelineStarts: [ - { - start: 100, - timeline: 100 - } + { start: 100, timeline: 100} ], uri: '' }, @@ -85,10 +82,7 @@ export const parsedManifest = { 'PROGRAM-ID': 1 }, discontinuitySequence: 1, - discontinuityStarts: [ - 2, - 4 - ], + discontinuityStarts: [2, 4], endList: false, mediaSequence: 0, resolvedUri: '', @@ -99,8 +93,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, - number: 0, presentationTime: 103, + number: 0, resolvedUri: 'http://example.com/audio/v0/000.m4f', timeline: 103, uri: '000.m4f' @@ -111,8 +105,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, - number: 1, presentationTime: 105, + number: 1, resolvedUri: 'http://example.com/audio/v0/001.m4f', timeline: 103, uri: '001.m4f' @@ -124,8 +118,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, - number: 2, presentationTime: 107, + number: 2, resolvedUri: 'http://example.com/audio/v0/000.m4f', timeline: 107, uri: '000.m4f' @@ -136,8 +130,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, - number: 3, presentationTime: 109, + number: 3, resolvedUri: 'http://example.com/audio/v0/001.m4f', timeline: 107, uri: '001.m4f' @@ -149,8 +143,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, - number: 4, presentationTime: 111, + number: 4, resolvedUri: 'http://example.com/audio/v0/862.m4f', timeline: 111, uri: '862.m4f' @@ -161,8 +155,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, - number: 5, presentationTime: 112, + number: 5, resolvedUri: 'http://example.com/audio/v0/863.m4f', timeline: 111, uri: '863.m4f' @@ -173,8 +167,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/audio/v0/init.mp4', uri: 'init.mp4' }, - number: 6, presentationTime: 113, + number: 6, resolvedUri: 'http://example.com/audio/v0/864.m4f', timeline: 111, uri: '864.m4f' @@ -183,18 +177,9 @@ export const parsedManifest = { targetDuration: 2, timeline: 103, timelineStarts: [ - { - start: 103, - timeline: 103 - }, - { - start: 107, - timeline: 107 - }, - { - start: 111, - timeline: 111 - } + { start: 103, timeline: 103}, + { start: 107, timeline: 107}, + { start: 111, timeline: 111} ], uri: '' } @@ -224,11 +209,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, discontinuitySequence: 0, - discontinuityStarts: [ - 3, - 5, - 7 - ], + discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, resolvedUri: '', @@ -239,8 +220,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 0, presentationTime: 100, + number: 0, resolvedUri: 'http://example.com/video/D/D500.m4f', timeline: 100, uri: 'D500.m4f' @@ -251,8 +232,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 1, presentationTime: 101, + number: 1, resolvedUri: 'http://example.com/video/D/D501.m4f', timeline: 100, uri: 'D501.m4f' @@ -263,8 +244,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 2, presentationTime: 102, + number: 2, resolvedUri: 'http://example.com/video/D/D502.m4f', timeline: 100, uri: 'D502.m4f' @@ -276,8 +257,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 3, presentationTime: 103, + number: 3, resolvedUri: 'http://example.com/video/D/D000.m4f', timeline: 103, uri: 'D000.m4f' @@ -288,8 +269,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 4, presentationTime: 105, + number: 4, resolvedUri: 'http://example.com/video/D/D001.m4f', timeline: 103, uri: 'D001.m4f' @@ -301,8 +282,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 5, presentationTime: 107, + number: 5, resolvedUri: 'http://example.com/video/D/D000.m4f', timeline: 107, uri: 'D000.m4f' @@ -313,8 +294,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 6, presentationTime: 109, + number: 6, resolvedUri: 'http://example.com/video/D/D001.m4f', timeline: 107, uri: 'D001.m4f' @@ -326,8 +307,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 7, presentationTime: 111, + number: 7, resolvedUri: 'http://example.com/video/D/D862.m4f', timeline: 111, uri: 'D862.m4f' @@ -338,8 +319,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 8, presentationTime: 112, + number: 8, resolvedUri: 'http://example.com/video/D/D863.m4f', timeline: 111, uri: 'D863.m4f' @@ -350,8 +331,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/D/D_init.mp4', uri: 'D_init.mp4' }, - number: 9, presentationTime: 113, + number: 9, resolvedUri: 'http://example.com/video/D/D864.m4f', timeline: 111, uri: 'D864.m4f' @@ -360,22 +341,10 @@ export const parsedManifest = { targetDuration: 1, timeline: 100, timelineStarts: [ - { - start: 100, - timeline: 100 - }, - { - start: 103, - timeline: 103 - }, - { - start: 107, - timeline: 107 - }, - { - start: 111, - timeline: 111 - } + { start: 100, timeline: 100}, + { start: 103, timeline: 103}, + { start: 107, timeline: 107}, + { start: 111, timeline: 111} ], uri: '' }, @@ -394,11 +363,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, discontinuitySequence: 0, - discontinuityStarts: [ - 3, - 5, - 7 - ], + discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, resolvedUri: '', @@ -409,8 +374,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 0, presentationTime: 100, + number: 0, resolvedUri: 'http://example.com/video/E/E500.m4f', timeline: 100, uri: 'E500.m4f' @@ -421,8 +386,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 1, presentationTime: 101, + number: 1, resolvedUri: 'http://example.com/video/E/E501.m4f', timeline: 100, uri: 'E501.m4f' @@ -433,8 +398,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 2, presentationTime: 102, + number: 2, resolvedUri: 'http://example.com/video/E/E502.m4f', timeline: 100, uri: 'E502.m4f' @@ -446,8 +411,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 3, presentationTime: 103, + number: 3, resolvedUri: 'http://example.com/video/E/E000.m4f', timeline: 103, uri: 'E000.m4f' @@ -458,8 +423,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 4, presentationTime: 105, + number: 4, resolvedUri: 'http://example.com/video/E/E001.m4f', timeline: 103, uri: 'E001.m4f' @@ -471,8 +436,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 5, presentationTime: 107, + number: 5, resolvedUri: 'http://example.com/video/E/E000.m4f', timeline: 107, uri: 'E000.m4f' @@ -483,8 +448,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 6, presentationTime: 109, + number: 6, resolvedUri: 'http://example.com/video/E/E001.m4f', timeline: 107, uri: 'E001.m4f' @@ -496,8 +461,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 7, presentationTime: 111, + number: 7, resolvedUri: 'http://example.com/video/E/E862.m4f', timeline: 111, uri: 'E862.m4f' @@ -508,8 +473,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 8, presentationTime: 112, + number: 8, resolvedUri: 'http://example.com/video/E/E863.m4f', timeline: 111, uri: 'E863.m4f' @@ -520,8 +485,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/E_init.mp4', uri: 'E_init.mp4' }, - number: 9, presentationTime: 113, + number: 9, resolvedUri: 'http://example.com/video/E/E864.m4f', timeline: 111, uri: 'E864.m4f' @@ -530,22 +495,10 @@ export const parsedManifest = { targetDuration: 1, timeline: 100, timelineStarts: [ - { - start: 100, - timeline: 100 - }, - { - start: 103, - timeline: 103 - }, - { - start: 107, - timeline: 107 - }, - { - start: 111, - timeline: 111 - } + { start: 100, timeline: 100}, + { start: 103, timeline: 103}, + { start: 107, timeline: 107}, + { start: 111, timeline: 111} ], uri: '' }, @@ -575,8 +528,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/F_init.mp4', uri: 'F_init.mp4' }, - number: 0, presentationTime: 100, + number: 0, resolvedUri: 'http://example.com/video/E/F500.m4f', timeline: 100, uri: 'F500.m4f' @@ -587,8 +540,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/F_init.mp4', uri: 'F_init.mp4' }, - number: 1, presentationTime: 101, + number: 1, resolvedUri: 'http://example.com/video/E/F501.m4f', timeline: 100, uri: 'F501.m4f' @@ -599,8 +552,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/F_init.mp4', uri: 'F_init.mp4' }, - number: 2, presentationTime: 102, + number: 2, resolvedUri: 'http://example.com/video/E/F502.m4f', timeline: 100, uri: 'F502.m4f' @@ -609,10 +562,7 @@ export const parsedManifest = { targetDuration: 1, timeline: 100, timelineStarts: [ - { - start: 100, - timeline: 100 - } + { start: 100, timeline: 100} ], uri: '' }, @@ -642,8 +592,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/C_init.mp4', uri: 'C_init.mp4' }, - number: 0, presentationTime: 100, + number: 0, resolvedUri: 'http://example.com/video/E/C500.m4f', timeline: 100, uri: 'C500.m4f' @@ -654,8 +604,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/C_init.mp4', uri: 'C_init.mp4' }, - number: 1, presentationTime: 101, + number: 1, resolvedUri: 'http://example.com/video/E/C501.m4f', timeline: 100, uri: 'C501.m4f' @@ -666,8 +616,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/E/C_init.mp4', uri: 'C_init.mp4' }, - number: 2, presentationTime: 102, + number: 2, resolvedUri: 'http://example.com/video/E/C502.m4f', timeline: 100, uri: 'C502.m4f' @@ -676,10 +626,7 @@ export const parsedManifest = { targetDuration: 1, timeline: 100, timelineStarts: [ - { - start: 100, - timeline: 100 - } + { start: 100, timeline: 100} ], uri: '' }, @@ -698,11 +645,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, discontinuitySequence: 0, - discontinuityStarts: [ - 3, - 5, - 7 - ], + discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, resolvedUri: '', @@ -713,8 +656,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 0, presentationTime: 100, + number: 0, resolvedUri: 'http://example.com/video/A/A500.m4f', timeline: 100, uri: 'A500.m4f' @@ -725,8 +668,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 1, presentationTime: 101, + number: 1, resolvedUri: 'http://example.com/video/A/A501.m4f', timeline: 100, uri: 'A501.m4f' @@ -737,8 +680,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 2, presentationTime: 102, + number: 2, resolvedUri: 'http://example.com/video/A/A502.m4f', timeline: 100, uri: 'A502.m4f' @@ -750,8 +693,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 3, presentationTime: 103, + number: 3, resolvedUri: 'http://example.com/video/A/A000.m4f', timeline: 103, uri: 'A000.m4f' @@ -762,8 +705,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 4, presentationTime: 105, + number: 4, resolvedUri: 'http://example.com/video/A/A001.m4f', timeline: 103, uri: 'A001.m4f' @@ -775,8 +718,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 5, presentationTime: 107, + number: 5, resolvedUri: 'http://example.com/video/A/A000.m4f', timeline: 107, uri: 'A000.m4f' @@ -787,8 +730,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 6, presentationTime: 109, + number: 6, resolvedUri: 'http://example.com/video/A/A001.m4f', timeline: 107, uri: 'A001.m4f' @@ -800,8 +743,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 7, presentationTime: 111, + number: 7, resolvedUri: 'http://example.com/video/A/A862.m4f', timeline: 111, uri: 'A862.m4f' @@ -812,8 +755,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 8, presentationTime: 112, + number: 8, resolvedUri: 'http://example.com/video/A/A863.m4f', timeline: 111, uri: 'A863.m4f' @@ -824,8 +767,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/A/A_init.mp4', uri: 'A_init.mp4' }, - number: 9, presentationTime: 113, + number: 9, resolvedUri: 'http://example.com/video/A/A864.m4f', timeline: 111, uri: 'A864.m4f' @@ -834,22 +777,10 @@ export const parsedManifest = { targetDuration: 1, timeline: 100, timelineStarts: [ - { - start: 100, - timeline: 100 - }, - { - start: 103, - timeline: 103 - }, - { - start: 107, - timeline: 107 - }, - { - start: 111, - timeline: 111 - } + { start: 100, timeline: 100}, + { start: 103, timeline: 103}, + { start: 107, timeline: 107}, + { start: 111, timeline: 111} ], uri: '' }, @@ -868,11 +799,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, discontinuitySequence: 0, - discontinuityStarts: [ - 3, - 5, - 7 - ], + discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, resolvedUri: '', @@ -883,8 +810,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 0, presentationTime: 100, + number: 0, resolvedUri: 'http://example.com/video/B/B500.m4f', timeline: 100, uri: 'B500.m4f' @@ -895,8 +822,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 1, presentationTime: 101, + number: 1, resolvedUri: 'http://example.com/video/B/B501.m4f', timeline: 100, uri: 'B501.m4f' @@ -907,8 +834,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 2, presentationTime: 102, + number: 2, resolvedUri: 'http://example.com/video/B/B502.m4f', timeline: 100, uri: 'B502.m4f' @@ -920,8 +847,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 3, presentationTime: 103, + number: 3, resolvedUri: 'http://example.com/video/B/B000.m4f', timeline: 103, uri: 'B000.m4f' @@ -932,8 +859,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 4, presentationTime: 105, + number: 4, resolvedUri: 'http://example.com/video/B/B001.m4f', timeline: 103, uri: 'B001.m4f' @@ -945,8 +872,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 5, presentationTime: 107, + number: 5, resolvedUri: 'http://example.com/video/B/B000.m4f', timeline: 107, uri: 'B000.m4f' @@ -957,8 +884,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 6, presentationTime: 109, + number: 6, resolvedUri: 'http://example.com/video/B/B001.m4f', timeline: 107, uri: 'B001.m4f' @@ -970,8 +897,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 7, presentationTime: 111, + number: 7, resolvedUri: 'http://example.com/video/B/B862.m4f', timeline: 111, uri: 'B862.m4f' @@ -982,8 +909,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 8, presentationTime: 112, + number: 8, resolvedUri: 'http://example.com/video/B/B863.m4f', timeline: 111, uri: 'B863.m4f' @@ -994,8 +921,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/B/B_init.mp4', uri: 'B_init.mp4' }, - number: 9, presentationTime: 113, + number: 9, resolvedUri: 'http://example.com/video/B/B864.m4f', timeline: 111, uri: 'B864.m4f' @@ -1004,22 +931,10 @@ export const parsedManifest = { targetDuration: 1, timeline: 100, timelineStarts: [ - { - start: 100, - timeline: 100 - }, - { - start: 103, - timeline: 103 - }, - { - start: 107, - timeline: 107 - }, - { - start: 111, - timeline: 111 - } + { start: 100, timeline: 100}, + { start: 103, timeline: 103}, + { start: 107, timeline: 107}, + { start: 111, timeline: 111} ], uri: '' }, @@ -1038,10 +953,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, discontinuitySequence: 1, - discontinuityStarts: [ - 2, - 4 - ], + discontinuityStarts: [2, 4], endList: false, mediaSequence: 0, resolvedUri: '', @@ -1052,8 +964,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/F/F_init.mp4', uri: 'F_init.mp4' }, - number: 0, presentationTime: 103, + number: 0, resolvedUri: 'http://example.com/video/F/F000.m4f', timeline: 103, uri: 'F000.m4f' @@ -1064,8 +976,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/F/F_init.mp4', uri: 'F_init.mp4' }, - number: 1, presentationTime: 105, + number: 1, resolvedUri: 'http://example.com/video/F/F001.m4f', timeline: 103, uri: 'F001.m4f' @@ -1077,8 +989,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/F/F_init.mp4', uri: 'F_init.mp4' }, - number: 2, presentationTime: 107, + number: 2, resolvedUri: 'http://example.com/video/F/F000.m4f', timeline: 107, uri: 'F000.m4f' @@ -1089,8 +1001,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/F/F_init.mp4', uri: 'F_init.mp4' }, - number: 3, presentationTime: 108, + number: 3, resolvedUri: 'http://example.com/video/F/F001.m4f', timeline: 107, uri: 'F001.m4f' @@ -1102,8 +1014,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/F/F_init.mp4', uri: 'F_init.mp4' }, - number: 4, presentationTime: 111, + number: 4, resolvedUri: 'http://example.com/video/F/F862.m4f', timeline: 111, uri: 'F862.m4f' @@ -1114,8 +1026,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/F/F_init.mp4', uri: 'F_init.mp4' }, - number: 5, presentationTime: 112, + number: 5, resolvedUri: 'http://example.com/video/F/F863.m4f', timeline: 111, uri: 'F863.m4f' @@ -1126,8 +1038,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/F/F_init.mp4', uri: 'F_init.mp4' }, - number: 6, presentationTime: 113, + number: 6, resolvedUri: 'http://example.com/video/F/F864.m4f', timeline: 111, uri: 'F864.m4f' @@ -1136,18 +1048,9 @@ export const parsedManifest = { targetDuration: 2, timeline: 103, timelineStarts: [ - { - start: 103, - timeline: 103 - }, - { - start: 107, - timeline: 107 - }, - { - start: 111, - timeline: 111 - } + { start: 103, timeline: 103}, + { start: 107, timeline: 107}, + { start: 111, timeline: 111} ], uri: '' }, @@ -1166,10 +1069,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, discontinuitySequence: 1, - discontinuityStarts: [ - 2, - 4 - ], + discontinuityStarts: [2, 4], endList: false, mediaSequence: 0, resolvedUri: '', @@ -1180,8 +1080,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, - number: 0, presentationTime: 103, + number: 0, resolvedUri: 'http://example.com/video/C/C000.m4f', timeline: 103, uri: 'C000.m4f' @@ -1192,8 +1092,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, - number: 1, presentationTime: 105, + number: 1, resolvedUri: 'http://example.com/video/C/C001.m4f', timeline: 103, uri: 'C001.m4f' @@ -1205,8 +1105,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, - number: 2, presentationTime: 107, + number: 2, resolvedUri: 'http://example.com/video/C/C000.m4f', timeline: 107, uri: 'C000.m4f' @@ -1217,8 +1117,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, - number: 3, presentationTime: 109, + number: 3, resolvedUri: 'http://example.com/video/C/C001.m4f', timeline: 107, uri: 'C001.m4f' @@ -1230,8 +1130,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, - number: 4, presentationTime: 111, + number: 4, resolvedUri: 'http://example.com/video/C/C862.m4f', timeline: 111, uri: 'C862.m4f' @@ -1242,8 +1142,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, - number: 5, presentationTime: 112, + number: 5, resolvedUri: 'http://example.com/video/C/C863.m4f', timeline: 111, uri: 'C863.m4f' @@ -1254,8 +1154,8 @@ export const parsedManifest = { resolvedUri: 'http://example.com/video/C/C_init.mp4', uri: 'C_init.mp4' }, - number: 6, presentationTime: 113, + number: 6, resolvedUri: 'http://example.com/video/C/C864.m4f', timeline: 111, uri: 'C864.m4f' @@ -1264,18 +1164,9 @@ export const parsedManifest = { targetDuration: 2, timeline: 103, timelineStarts: [ - { - start: 103, - timeline: 103 - }, - { - start: 107, - timeline: 107 - }, - { - start: 111, - timeline: 111 - } + { start: 103, timeline: 103}, + { start: 107, timeline: 107}, + { start: 111, timeline: 111} ], uri: '' } From 6b6efd16f79d55dfbf9d44c9621fdf8649303320 Mon Sep 17 00:00:00 2001 From: wseymour15 Date: Fri, 25 Aug 2023 11:53:49 -0500 Subject: [PATCH 6/7] remove serviceLocation from segments --- src/segment/segmentTemplate.js | 7 +------ src/segment/urlType.js | 8 +------- test/toPlaylists.test.js | 12 +----------- 3 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/segment/segmentTemplate.js b/src/segment/segmentTemplate.js index e8b92982..673887de 100644 --- a/src/segment/segmentTemplate.js +++ b/src/segment/segmentTemplate.js @@ -147,8 +147,7 @@ export const segmentsFromTemplate = (attributes, segmentTimeline) => { const mapSegment = urlTypeToSegment({ baseUrl: attributes.baseUrl, source: constructTemplateUrl(initialization.sourceURL, templateValues), - range: initialization.range, - serviceLocation: attributes.serviceLocation + range: initialization.range }); const segments = parseTemplateInfo(attributes, segmentTimeline); @@ -178,10 +177,6 @@ export const segmentsFromTemplate = (attributes, segmentTimeline) => { presentationTime }; - if (attributes.serviceLocation) { - map.serviceLocation = attributes.serviceLocation; - } - return map; }); }; diff --git a/src/segment/urlType.js b/src/segment/urlType.js index a1d87853..ae04f754 100644 --- a/src/segment/urlType.js +++ b/src/segment/urlType.js @@ -23,21 +23,15 @@ import window from 'global/window'; * @param {string} source - source url for segment * @param {string} range - optional range used for range calls, * follows RFC 2616, Clause 14.35.1 - * @param {string} serviceLocation - optional serviceLocation provided by nodes - * used for content steering * @return {SingleUri} full segment information transformed into a format similar * to m3u8-parser */ -export const urlTypeToSegment = ({ baseUrl = '', source = '', range = '', serviceLocation = null, indexRange = '' }) => { +export const urlTypeToSegment = ({ baseUrl = '', source = '', range = '', indexRange = '' }) => { const segment = { uri: source, resolvedUri: resolveUrl(baseUrl || '', source) }; - if (serviceLocation) { - segment.serviceLocation = serviceLocation; - } - if (range || indexRange) { const rangeStr = range ? range : indexRange; const ranges = rangeStr.split('-'); diff --git a/test/toPlaylists.test.js b/test/toPlaylists.test.js index 31760e42..0331c267 100644 --- a/test/toPlaylists.test.js +++ b/test/toPlaylists.test.js @@ -187,13 +187,11 @@ QUnit.test('playlist with content steering BaseURLs', function(assert) { duration: 0, map: { resolvedUri: 'https://cdn1.example.com/', - serviceLocation: 'alpha', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/', - serviceLocation: 'alpha', timeline: 0, uri: '' } @@ -222,13 +220,11 @@ QUnit.test('playlist with content steering BaseURLs', function(assert) { duration: 0, map: { resolvedUri: 'https://cdn2.example.com/', - serviceLocation: 'beta', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn2.example.com/', - serviceLocation: 'beta', timeline: 0, uri: '' } @@ -522,13 +518,11 @@ QUnit.test('playlist with content steering and resolvable BaseURLs', function(as duration: 0, map: { resolvedUri: 'https://cdn1.example.com/video', - uri: '', - serviceLocation: 'alpha' + uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/video', - serviceLocation: 'alpha', timeline: 0, uri: '' } @@ -558,13 +552,11 @@ QUnit.test('playlist with content steering and resolvable BaseURLs', function(as duration: 0, map: { resolvedUri: 'https://cdn2.example.com/video', - serviceLocation: 'beta', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn2.example.com/video', - serviceLocation: 'beta', timeline: 0, uri: '' } @@ -590,13 +582,11 @@ QUnit.test('playlist with content steering and resolvable BaseURLs', function(as duration: 0, map: { resolvedUri: 'https://cdn1.example.com/vtt', - serviceLocation: 'alpha', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/vtt', - serviceLocation: 'alpha', timeline: 0, uri: '' } From 5473498f1824ed2420f730efb588da37e85b1696 Mon Sep 17 00:00:00 2001 From: wseymour15 Date: Fri, 25 Aug 2023 15:39:27 -0500 Subject: [PATCH 7/7] add resolvedURIs to video and audio playlists --- src/toM3u8.js | 10 ++-- test/manifests/608-captions.js | 2 +- test/manifests/708-captions.js | 2 +- test/manifests/audio-only.js | 4 +- test/manifests/location.js | 2 +- test/manifests/locations.js | 2 +- test/manifests/maat_vtt_segmentTemplate.js | 12 ++--- test/manifests/multiperiod-segment-list.js | 2 +- .../manifests/multiperiod-segment-template.js | 4 +- ...multiperiod-startnumber-removed-periods.js | 14 +++--- test/manifests/multiperiod-startnumber.js | 20 ++++---- test/manifests/segmentBase.js | 2 +- test/manifests/segmentList.js | 4 +- test/manifests/vtt_codecs.js | 12 ++--- test/manifests/webmsegments.js | 4 +- test/toM3u8.test.js | 46 +++++++------------ 16 files changed, 65 insertions(+), 77 deletions(-) diff --git a/src/toM3u8.js b/src/toM3u8.js index 79b1e98f..287f7da9 100644 --- a/src/toM3u8.js +++ b/src/toM3u8.js @@ -115,7 +115,7 @@ export const formatAudioPlaylist = ({ uri: '', endList: attributes.type === 'static', timeline: attributes.periodStart, - resolvedUri: '', + resolvedUri: attributes.baseUrl || '', targetDuration: attributes.duration, discontinuitySequence, discontinuityStarts, @@ -129,7 +129,7 @@ export const formatAudioPlaylist = ({ } if (attributes.serviceLocation) { - playlist.serviceLocation = attributes.serviceLocation; + playlist.attributes.serviceLocation = attributes.serviceLocation; } if (sidx) { @@ -189,7 +189,7 @@ export const formatVttPlaylist = ({ }; if (attributes.serviceLocation) { - vttPlaylist.serviceLocation = attributes.serviceLocation; + vttPlaylist.attributes.serviceLocation = attributes.serviceLocation; } return vttPlaylist; @@ -317,7 +317,7 @@ export const formatVideoPlaylist = ({ uri: '', endList: attributes.type === 'static', timeline: attributes.periodStart, - resolvedUri: '', + resolvedUri: attributes.baseUrl || '', targetDuration: attributes.duration, discontinuityStarts, timelineStarts: attributes.timelineStarts, @@ -333,7 +333,7 @@ export const formatVideoPlaylist = ({ } if (attributes.serviceLocation) { - playlist.serviceLocation = attributes.serviceLocation; + playlist.attributes.serviceLocation = attributes.serviceLocation; } if (sidx) { diff --git a/test/manifests/608-captions.js b/test/manifests/608-captions.js index ae12c995..cf505439 100644 --- a/test/manifests/608-captions.js +++ b/test/manifests/608-captions.js @@ -46,7 +46,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: true, - resolvedUri: '', + resolvedUri: 'https://www.example.com/1080p.ts', targetDuration: 6, mediaSequence: 0, timelineStarts: [{ start: 0, timeline: 0 }], diff --git a/test/manifests/708-captions.js b/test/manifests/708-captions.js index 4b3e682a..5df7a048 100644 --- a/test/manifests/708-captions.js +++ b/test/manifests/708-captions.js @@ -47,7 +47,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: true, - resolvedUri: '', + resolvedUri: 'https://www.example.com/1080p.ts', targetDuration: 6, mediaSequence: 0, timelineStarts: [{ start: 0, timeline: 0 }], diff --git a/test/manifests/audio-only.js b/test/manifests/audio-only.js index be2d860c..e93327ec 100644 --- a/test/manifests/audio-only.js +++ b/test/manifests/audio-only.js @@ -27,7 +27,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/audio_en_2c_128k_aac.mp4', targetDuration: 60, segments: [], mediaSequence: 0, @@ -78,7 +78,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/audio_es_2c_128k_aac.mp4', targetDuration: 60, segments: [], mediaSequence: 0, diff --git a/test/manifests/location.js b/test/manifests/location.js index c7fe2469..6b9ae7b9 100644 --- a/test/manifests/location.js +++ b/test/manifests/location.js @@ -32,7 +32,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: true, - resolvedUri: '', + resolvedUri: 'https://www.example.com/1080p.ts', targetDuration: 6, mediaSequence: 0, discontinuitySequence: 0, diff --git a/test/manifests/locations.js b/test/manifests/locations.js index 6b2ac590..86911edf 100644 --- a/test/manifests/locations.js +++ b/test/manifests/locations.js @@ -33,7 +33,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: true, - resolvedUri: '', + resolvedUri: 'https://www.example.com/1080p.ts', targetDuration: 6, mediaSequence: 0, discontinuitySequence: 0, diff --git a/test/manifests/maat_vtt_segmentTemplate.js b/test/manifests/maat_vtt_segmentTemplate.js index b7bbc6e9..38894c9c 100644 --- a/test/manifests/maat_vtt_segmentTemplate.js +++ b/test/manifests/maat_vtt_segmentTemplate.js @@ -25,7 +25,7 @@ export const parsedManifest = { timelineStarts: [{ start: 0, timeline: 0 }], discontinuitySequence: 0, discontinuityStarts: [], - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -100,7 +100,7 @@ export const parsedManifest = { timelineStarts: [{ start: 0, timeline: 0 }], discontinuitySequence: 0, discontinuityStarts: [], - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -183,7 +183,7 @@ export const parsedManifest = { timelineStarts: [{ start: 0, timeline: 0 }], discontinuitySequence: 0, discontinuityStarts: [], - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -258,7 +258,7 @@ export const parsedManifest = { timelineStarts: [{ start: 0, timeline: 0 }], discontinuitySequence: 0, discontinuityStarts: [], - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -421,7 +421,7 @@ export const parsedManifest = { timelineStarts: [{ start: 0, timeline: 0 }], discontinuitySequence: 0, discontinuityStarts: [], - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.9185833333333333, segments: [ { @@ -503,7 +503,7 @@ export const parsedManifest = { timelineStarts: [{ start: 0, timeline: 0 }], discontinuitySequence: 0, discontinuityStarts: [], - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.9185833333333333, segments: [ { diff --git a/test/manifests/multiperiod-segment-list.js b/test/manifests/multiperiod-segment-list.js index aaf8be6e..fefcccad 100644 --- a/test/manifests/multiperiod-segment-list.js +++ b/test/manifests/multiperiod-segment-list.js @@ -36,7 +36,7 @@ export const parsedManifest = { timeline: 6 }], targetDuration: 3, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', segments: [ { duration: 3, diff --git a/test/manifests/multiperiod-segment-template.js b/test/manifests/multiperiod-segment-template.js index 6cc21b98..139a3a75 100644 --- a/test/manifests/multiperiod-segment-template.js +++ b/test/manifests/multiperiod-segment-template.js @@ -30,7 +30,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 5, segments: [ { @@ -145,7 +145,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 5, segments: [ { diff --git a/test/manifests/multiperiod-startnumber-removed-periods.js b/test/manifests/multiperiod-startnumber-removed-periods.js index 6c444b47..fdcbf5ca 100644 --- a/test/manifests/multiperiod-startnumber-removed-periods.js +++ b/test/manifests/multiperiod-startnumber-removed-periods.js @@ -31,7 +31,7 @@ export const parsedManifest = { timelineStarts: [ { start: 111, timeline: 111} ], - resolvedUri: '', + resolvedUri: 'http://example.com/audio/v0/', segments: [ { discontinuity: true, @@ -107,7 +107,7 @@ export const parsedManifest = { timelineStarts: [ { start: 111, timeline: 111} ], - resolvedUri: '', + resolvedUri: 'http://example.com/video/D/', segments: [ { discontinuity: true, @@ -172,7 +172,7 @@ export const parsedManifest = { { start: 111, timeline: 111} ], discontinuityStarts: [0], - resolvedUri: '', + resolvedUri: 'http://example.com/video/E/', segments: [ { discontinuity: true, @@ -237,7 +237,7 @@ export const parsedManifest = { { start: 111, timeline: 111} ], discontinuityStarts: [0], - resolvedUri: '', + resolvedUri: 'http://example.com/video/F/', segments: [ { discontinuity: true, @@ -302,7 +302,7 @@ export const parsedManifest = { { start: 111, timeline: 111} ], discontinuityStarts: [0], - resolvedUri: '', + resolvedUri: 'http://example.com/video/A/', segments: [ { discontinuity: true, @@ -367,7 +367,7 @@ export const parsedManifest = { { start: 111, timeline: 111} ], discontinuityStarts: [0], - resolvedUri: '', + resolvedUri: 'http://example.com/video/B/', segments: [ { discontinuity: true, @@ -432,7 +432,7 @@ export const parsedManifest = { { start: 111, timeline: 111} ], discontinuityStarts: [0], - resolvedUri: '', + resolvedUri: 'http://example.com/video/C/', segments: [ { discontinuity: true, diff --git a/test/manifests/multiperiod-startnumber.js b/test/manifests/multiperiod-startnumber.js index 1da9d25a..9d453589 100644 --- a/test/manifests/multiperiod-startnumber.js +++ b/test/manifests/multiperiod-startnumber.js @@ -28,7 +28,7 @@ export const parsedManifest = { mediaSequence: 0, discontinuitySequence: 0, discontinuityStarts: [], - resolvedUri: '', + resolvedUri: 'http://example.com/audio/1', segments: [ { duration: 1, @@ -85,7 +85,7 @@ export const parsedManifest = { discontinuityStarts: [2, 4], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/audio/v0/', segments: [ { duration: 2, @@ -212,7 +212,7 @@ export const parsedManifest = { discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/D/', segments: [ { duration: 1, @@ -366,7 +366,7 @@ export const parsedManifest = { discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/E/', segments: [ { duration: 1, @@ -520,7 +520,7 @@ export const parsedManifest = { discontinuityStarts: [], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/E/', segments: [ { duration: 1, @@ -584,7 +584,7 @@ export const parsedManifest = { discontinuityStarts: [], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/E/', segments: [ { duration: 1, @@ -648,7 +648,7 @@ export const parsedManifest = { discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/A/', segments: [ { duration: 1, @@ -802,7 +802,7 @@ export const parsedManifest = { discontinuityStarts: [3, 5, 7], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/B/', segments: [ { duration: 1, @@ -956,7 +956,7 @@ export const parsedManifest = { discontinuityStarts: [2, 4], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/F/', segments: [ { duration: 2, @@ -1072,7 +1072,7 @@ export const parsedManifest = { discontinuityStarts: [2, 4], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'http://example.com/video/C/', segments: [ { duration: 2, diff --git a/test/manifests/segmentBase.js b/test/manifests/segmentBase.js index f45ab909..59258647 100644 --- a/test/manifests/segmentBase.js +++ b/test/manifests/segmentBase.js @@ -25,7 +25,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: true, - resolvedUri: '', + resolvedUri: 'https://www.example.com/1080p.ts', targetDuration: 6, mediaSequence: 0, segments: [ diff --git a/test/manifests/segmentList.js b/test/manifests/segmentList.js index 9b7ddce8..3220b4a3 100644 --- a/test/manifests/segmentList.js +++ b/test/manifests/segmentList.js @@ -27,7 +27,7 @@ export const parsedManifest = { endList: true, mediaSequence: 0, targetDuration: 1, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', segments: [ { duration: 1, @@ -123,7 +123,7 @@ export const parsedManifest = { 'SUBTITLES': 'subs' }, endList: true, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', mediaSequence: 0, targetDuration: 60, segments: [ diff --git a/test/manifests/vtt_codecs.js b/test/manifests/vtt_codecs.js index 46dcbae9..aa80010a 100644 --- a/test/manifests/vtt_codecs.js +++ b/test/manifests/vtt_codecs.js @@ -25,7 +25,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -103,7 +103,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -189,7 +189,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -267,7 +267,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.984, segments: [ { @@ -440,7 +440,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.9185833333333333, segments: [ { @@ -525,7 +525,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 1.9185833333333333, segments: [ { diff --git a/test/manifests/webmsegments.js b/test/manifests/webmsegments.js index daae0108..ed376c6a 100644 --- a/test/manifests/webmsegments.js +++ b/test/manifests/webmsegments.js @@ -22,7 +22,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 4, segments: [ { @@ -108,7 +108,7 @@ export const parsedManifest = { uri: '', endList: true, timeline: 0, - resolvedUri: '', + resolvedUri: 'https://www.example.com/base', targetDuration: 4, segments: [ { diff --git a/test/toM3u8.test.js b/test/toM3u8.test.js index e527d097..6d28e6b4 100644 --- a/test/toM3u8.test.js +++ b/test/toM3u8.test.js @@ -246,13 +246,11 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser duration: 0, map: { resolvedUri: 'https://cdn1.example.com/video', - uri: '', - serviceLocation: 'alpha' + uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/video', - serviceLocation: 'alpha', timeline: 0, uri: '' } @@ -282,13 +280,11 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser duration: 0, map: { resolvedUri: 'https://cdn2.example.com/video', - serviceLocation: 'beta', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn2.example.com/video', - serviceLocation: 'beta', timeline: 0, uri: '' } @@ -314,13 +310,11 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser duration: 0, map: { resolvedUri: 'https://cdn1.example.com/vtt', - serviceLocation: 'alpha', uri: '' }, number: 1, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/vtt', - serviceLocation: 'alpha', timeline: 0, uri: '' } @@ -368,7 +362,8 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser attributes: { BANDWIDTH: 256, NAME: 'en', - ['PROGRAM-ID']: 1 + ['PROGRAM-ID']: 1, + serviceLocation: 'alpha' }, discontinuitySequence: 0, discontinuityStarts: [], @@ -380,18 +375,15 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser duration: 0, map: { resolvedUri: 'https://cdn1.example.com/vtt', - serviceLocation: 'alpha', uri: '' }, number: 0, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/vtt', - serviceLocation: 'alpha', timeline: 0, uri: '' } ], - serviceLocation: 'alpha', targetDuration: 0, timeline: 0, timelineStarts: [ @@ -406,7 +398,8 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser attributes: { BANDWIDTH: 256, NAME: 'en', - ['PROGRAM-ID']: 1 + ['PROGRAM-ID']: 1, + serviceLocation: 'beta' }, discontinuitySequence: 0, discontinuityStarts: [], @@ -422,7 +415,6 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser uri: 'https://cdn2.example.com/vtt' } ], - serviceLocation: 'beta', targetDuration: 0, timeline: 0, timelineStarts: [ @@ -452,30 +444,28 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser height: 404, width: 720 }, - SUBTITLES: 'subs' + SUBTITLES: 'subs', + serviceLocation: 'alpha' }, discontinuitySequence: 0, discontinuityStarts: [], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'https://cdn1.example.com/video', segments: [ { duration: 0, map: { resolvedUri: 'https://cdn1.example.com/video', - serviceLocation: 'alpha', uri: '' }, number: 0, presentationTime: 0, resolvedUri: 'https://cdn1.example.com/video', - serviceLocation: 'alpha', timeline: 0, uri: '' } ], - serviceLocation: 'alpha', targetDuration: 0, timeline: 0, timelineStarts: [ @@ -497,30 +487,28 @@ QUnit.test('playlists with content steering and resolvable URLs', function(asser height: 404, width: 720 }, - SUBTITLES: 'subs' + SUBTITLES: 'subs', + serviceLocation: 'beta' }, discontinuitySequence: 0, discontinuityStarts: [], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'https://cdn2.example.com/video', segments: [ { duration: 0, map: { resolvedUri: 'https://cdn2.example.com/video', - serviceLocation: 'beta', uri: '' }, number: 0, presentationTime: 0, resolvedUri: 'https://cdn2.example.com/video', - serviceLocation: 'beta', timeline: 0, uri: '' } ], - serviceLocation: 'beta', targetDuration: 0, timeline: 0, timelineStarts: [ @@ -721,13 +709,14 @@ QUnit.test('playlists with content steering', function(assert) { height: 404, width: 720 }, - SUBTITLES: 'subs' + SUBTITLES: 'subs', + serviceLocation: 'alpha' }, discontinuitySequence: 0, discontinuityStarts: [], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'https://cdn1.example.com/', segments: [ { duration: 0, @@ -742,7 +731,6 @@ QUnit.test('playlists with content steering', function(assert) { uri: '' } ], - serviceLocation: 'alpha', targetDuration: 0, timeline: 0, timelineStarts: [ @@ -764,13 +752,14 @@ QUnit.test('playlists with content steering', function(assert) { height: 404, width: 720 }, - SUBTITLES: 'subs' + SUBTITLES: 'subs', + serviceLocation: 'beta' }, discontinuitySequence: 0, discontinuityStarts: [], endList: false, mediaSequence: 0, - resolvedUri: '', + resolvedUri: 'https://cdn2.example.com/', segments: [ { duration: 0, @@ -785,7 +774,6 @@ QUnit.test('playlists with content steering', function(assert) { uri: '' } ], - serviceLocation: 'beta', targetDuration: 0, timeline: 0, timelineStarts: [