Skip to content

Commit

Permalink
feat: limited multiperiod support (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
forbesjo authored Oct 24, 2018
1 parent 90feb2d commit aee87a0
Show file tree
Hide file tree
Showing 8 changed files with 1,195 additions and 7 deletions.
10 changes: 7 additions & 3 deletions src/inheritAttributes.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import window from 'global/window';
import { flatten } from './utils/list';
import { merge } from './utils/object';
import { findChildren, getContent } from './utils/xml';
Expand Down Expand Up @@ -269,8 +270,12 @@ export const toRepresentations =
* @return {toAdaptationSetsCallback}
* Callback map function
*/
export const toAdaptationSets = (mpdAttributes, mpdBaseUrls) => (period, periodIndex) => {
export const toAdaptationSets = (mpdAttributes, mpdBaseUrls) => (period, index) => {
const periodBaseUrls = buildBaseUrls(mpdBaseUrls, findChildren(period, 'BaseURL'));
const periodAtt = parseAttributes(period);
const parsedPeriodId = parseInt(periodAtt.id, 10);
// fallback to mapping index if Period@id is not a number
const periodIndex = window.isNaN(parsedPeriodId) ? index : parsedPeriodId;
const periodAttributes = merge(mpdAttributes, { periodIndex });
const adaptationSets = findChildren(period, 'AdaptationSet');
const periodSegmentInfo = getSegmentInformation(period);
Expand Down Expand Up @@ -304,8 +309,7 @@ export const inheritAttributes = (mpd, options = {}) => {
} = options;
const periods = findChildren(mpd, 'Period');

if (periods.length !== 1) {
// TODO add support for multiperiod
if (!periods.length) {
throw new Error(errors.INVALID_NUMBER_OF_PERIOD);
}

Expand Down
44 changes: 42 additions & 2 deletions src/toM3u8.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
import { values } from './utils/object';
import { findIndexes } from './utils/list';

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 || '');

// Periods after first
if (acc[name]) {
// first segment of subsequent periods signal a discontinuity
playlist.segments[0].discontinuity = true;
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;
}
} else {
// first Period
acc[name] = playlist;
}

return acc;
}, {}));

return mergedPlaylists.map(playlist => {
playlist.discontinuityStarts =
findIndexes(playlist.segments, 'discontinuity');

return playlist;
});
};

export const formatAudioPlaylist = ({ attributes, segments }) => {
const playlist = {
attributes: {
Expand Down Expand Up @@ -151,8 +189,10 @@ export const toM3u8 = dashPlaylists => {
const vttOnly = ({ attributes }) =>
attributes.mimeType === 'text/vtt' || attributes.contentType === 'text';

const videoPlaylists = dashPlaylists.filter(videoOnly).map(formatVideoPlaylist);
const audioPlaylists = dashPlaylists.filter(audioOnly);
const videoPlaylists = mergeDiscontiguousPlaylists(
dashPlaylists.filter(videoOnly)
).map(formatVideoPlaylist);
const audioPlaylists = mergeDiscontiguousPlaylists(dashPlaylists.filter(audioOnly));
const vttPlaylists = dashPlaylists.filter(vttOnly);

const master = {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,11 @@ export const from = list => {

return result;
};

export const findIndexes = (l, key) => l.reduce((a, e, i) => {
if (e[key]) {
a.push(i);
}

return a;
}, []);
2 changes: 2 additions & 0 deletions src/utils/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ export const merge = (...objects) => {
return result;
}, {});
};

export const values = o => Object.keys(o).map(k => o[k]);
9 changes: 9 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import QUnit from 'qunit';
import maatVttSegmentTemplate from './manifests/maat_vtt_segmentTemplate.mpd';
import segmentBaseTemplate from './manifests/segmentBase.mpd';
import segmentListTemplate from './manifests/segmentList.mpd';
import multiperiod from './manifests/multiperiod.mpd';
import {
parsedManifest as maatVttSegmentTemplateManifest
} from './manifests/maat_vtt_segmentTemplate.js';
Expand All @@ -14,6 +15,10 @@ import {
import {
parsedManifest as segmentListManifest
} from './manifests/segmentList.js';
import {
parsedManifest as multiperiodManifest
} from './manifests/multiperiod.js';

QUnit.module('mpd-parser');

QUnit.test('has VERSION', function(assert) {
Expand All @@ -36,6 +41,10 @@ QUnit.test('has parse', function(assert) {
name: 'segmentList',
input: segmentListTemplate,
expected: segmentListManifest
}, {
name: 'multiperiod',
input: multiperiod,
expected: multiperiodManifest
}].forEach(({ name, input, expected }) => {
QUnit.test(`${name} test manifest`, function(assert) {
const actual = parse(input);
Expand Down
Loading

0 comments on commit aee87a0

Please sign in to comment.