Skip to content

Commit

Permalink
feat: support in-manifest DRM data (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
forbesjo authored Mar 30, 2018
1 parent 34a6173 commit a1cad82
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 55 deletions.
37 changes: 29 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"serve-static": "^1.13.2",
"sinon": "^1.10.3",
"uglify-es": "^3.3.9",
"videojs-contrib-eme": "^3.0.0",
"videojs-contrib-eme": "^3.2.0",
"videojs-contrib-quality-levels": "^2.0.4",
"videojs-standard": "^4.0.3"
}
Expand Down
23 changes: 16 additions & 7 deletions src/videojs-http-streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Hls.canPlaySource = function() {
'your player\'s techOrder.');
};

const emeOptions = (keySystemOptions, videoPlaylist, audioPlaylist) => {
const emeKeySystems = (keySystemOptions, videoPlaylist, audioPlaylist) => {
if (!keySystemOptions) {
return keySystemOptions;
}
Expand All @@ -151,16 +151,21 @@ const emeOptions = (keySystemOptions, videoPlaylist, audioPlaylist) => {
videoContentType: `video/mp4; codecs="${videoPlaylist.attributes.CODECS}"`
};

if (videoPlaylist.contentProtection &&
videoPlaylist.contentProtection[keySystem] &&
videoPlaylist.contentProtection[keySystem].pssh) {
keySystemContentTypes[keySystem].pssh =
videoPlaylist.contentProtection[keySystem].pssh;
}

// videojs-contrib-eme accepts the option of specifying: 'com.some.cdm': 'url'
// so we need to prevent overwriting the URL entirely
if (typeof keySystemOptions[keySystem] === 'string') {
keySystemContentTypes[keySystem].url = keySystemOptions[keySystem];
}
}

return {
keySystems: videojs.mergeOptions(keySystemOptions, keySystemContentTypes)
};
return videojs.mergeOptions(keySystemOptions, keySystemContentTypes);
};

const setupEmeOptions = (hlsHandler) => {
Expand All @@ -170,11 +175,15 @@ const setupEmeOptions = (hlsHandler) => {
const player = videojs.players[hlsHandler.tech_.options_.playerId];

if (player.eme) {
player.eme.options = videojs.mergeOptions(player.eme.options, emeOptions(
const sourceOptions = emeKeySystems(
hlsHandler.source_.keySystems,
hlsHandler.playlists.media(),
hlsHandler.masterPlaylistController_.mediaTypes_.AUDIO.activePlaylistLoader.media()
));
);

if (sourceOptions) {
player.currentSource().keySystems = sourceOptions;
}
}
};

Expand Down Expand Up @@ -705,6 +714,6 @@ export {
Hls,
HlsHandler,
HlsSourceHandler,
emeOptions,
emeKeySystems,
simpleTypeFromSourceType
};
130 changes: 91 additions & 39 deletions test/videojs-http-streaming.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
HlsSourceHandler,
HlsHandler,
Hls,
emeOptions,
emeKeySystems,
simpleTypeFromSourceType
} from '../src/videojs-http-streaming';
import window from 'global/window';
Expand Down Expand Up @@ -2865,6 +2865,11 @@ QUnit.test('configures eme if present on selectedinitialmedia', function(assert)
return {
attributes: {
CODECS: 'video-codec'
},
contentProtection: {
keySystem1: {
pssh: 'test'
}
}
};
},
Expand All @@ -2889,15 +2894,68 @@ QUnit.test('configures eme if present on selectedinitialmedia', function(assert)
this.player.tech_.hls.masterPlaylistController_.trigger('selectedinitialmedia');

assert.deepEqual(this.player.eme.options, {
previousSetting: 1,
previousSetting: 1
}, 'did not modify plugin options');

assert.deepEqual(this.player.currentSource(), {
src: 'manifest/master.mpd',
type: 'application/dash+xml',
keySystems: {
keySystem1: {
url: 'url1',
audioContentType: 'audio/mp4; codecs="audio-codec"',
videoContentType: 'video/mp4; codecs="video-codec"'
videoContentType: 'video/mp4; codecs="video-codec"',
pssh: 'test'
}
}
}, 'set source eme options');
});

QUnit.test('does not set source keySystems if keySystems not provided by source', function(assert) {
this.player.src({
src: 'manifest/master.mpd',
type: 'application/dash+xml'
});

this.clock.tick(1);

this.player.tech_.hls.playlists = {
media: () => {
return {
attributes: {
CODECS: 'video-codec'
},
contentProtection: {
keySystem1: {
pssh: 'test'
}
}
};
},
// mocked for renditions mixin
master: {
playlists: []
}
};
this.player.tech_.hls.masterPlaylistController_.mediaTypes_ = {
AUDIO: {
activePlaylistLoader: {
media: () => {
return {
attributes: {
CODECS: 'audio-codec'
}
};
}
}
}
}, 'set eme options');
};
this.player.tech_.hls.masterPlaylistController_.trigger('selectedinitialmedia');

assert.deepEqual(this.player.currentSource(), {
src: 'manifest/master.mpd',
type: 'application/dash+xml'
}, 'does not set source eme options');
});

QUnit.module('HLS Integration', {
Expand Down Expand Up @@ -3306,53 +3364,49 @@ QUnit.test('treats invalid keys as a key request failure and blacklists playlist

QUnit.module('videojs-contrib-hls isolated functions');

QUnit.test('emeOptions adds content types for all keySystems', function(assert) {
QUnit.test('emeKeySystems adds content types for all keySystems', function(assert) {
assert.deepEqual(
emeOptions(
emeKeySystems(
{ keySystem1: {}, keySystem2: {} },
{ attributes: { CODECS: 'some-video-codec' } },
{ attributes: { CODECS: 'some-audio-codec' } }),
{
keySystems: {
keySystem1: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
},
keySystem2: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
}
keySystem1: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
},
keySystem2: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
}
},
'added content types');
});

QUnit.test('emeOptions retains non content type properties', function(assert) {
QUnit.test('emeKeySystems retains non content type properties', function(assert) {
assert.deepEqual(
emeOptions(
emeKeySystems(
{ keySystem1: { url: '1' }, keySystem2: { url: '2'} },
{ attributes: { CODECS: 'some-video-codec' } },
{ attributes: { CODECS: 'some-audio-codec' } }),
{
keySystems: {
keySystem1: {
url: '1',
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
},
keySystem2: {
url: '2',
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
}
keySystem1: {
url: '1',
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
},
keySystem2: {
url: '2',
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
}
},
'retained options');
});

QUnit.test('emeOptions overwrites content types', function(assert) {
QUnit.test('emeKeySystems overwrites content types', function(assert) {
assert.deepEqual(
emeOptions(
emeKeySystems(
{
keySystem1: {
audioContentType: 'a',
Expand All @@ -3366,15 +3420,13 @@ QUnit.test('emeOptions overwrites content types', function(assert) {
{ attributes: { CODECS: 'some-video-codec' } },
{ attributes: { CODECS: 'some-audio-codec' } }),
{
keySystems: {
keySystem1: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
},
keySystem2: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
}
keySystem1: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
},
keySystem2: {
audioContentType: 'audio/mp4; codecs="some-audio-codec"',
videoContentType: 'video/mp4; codecs="some-video-codec"'
}
},
'overwrote content types');
Expand Down

0 comments on commit a1cad82

Please sign in to comment.