Skip to content

Commit 1c62a98

Browse files
alex-barstowmisteroneill
authored andcommitted
fix: output-restricted event handling for unplayable streams (#1305)
1 parent 57c0e72 commit 1c62a98

File tree

2 files changed

+88
-29
lines changed

2 files changed

+88
-29
lines changed

src/videojs-http-streaming.js

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,15 +1017,40 @@ class VhsHandler extends Component {
10171017
});
10181018

10191019
this.player_.tech_.on('keystatuschange', (e) => {
1020-
if (e.status === 'output-restricted') {
1021-
this.playlistController_.excludePlaylist({
1022-
playlistToExclude: this.playlistController_.media(),
1023-
error: {
1024-
message: `DRM keystatus changed to ${e.status}. Playlist will fail to play. ` +
1025-
'Check for HDCP content.'
1026-
},
1027-
playlistExclusionDuration: Infinity
1028-
});
1020+
if (e.status !== 'output-restricted') {
1021+
return;
1022+
}
1023+
1024+
const mainPlaylist = this.playlistController_.main();
1025+
1026+
if (!mainPlaylist || !mainPlaylist.playlists) {
1027+
return;
1028+
}
1029+
1030+
const excludedHDPlaylists = [];
1031+
1032+
// Assume all HD streams are unplayable and exclude them from ABR selection
1033+
mainPlaylist.playlists.forEach(playlist => {
1034+
if (playlist && playlist.attributes && playlist.attributes.RESOLUTION &&
1035+
playlist.attributes.RESOLUTION.height >= 720) {
1036+
if (!playlist.excludeUntil || playlist.excludeUntil < Infinity) {
1037+
1038+
playlist.excludeUntil = Infinity;
1039+
excludedHDPlaylists.push(playlist);
1040+
}
1041+
}
1042+
});
1043+
1044+
if (excludedHDPlaylists.length) {
1045+
videojs.log.warn(
1046+
'DRM keystatus changed to "output-restricted." Removing the following HD playlists ' +
1047+
'that will most likely fail to play and clearing the buffer. ' +
1048+
'This may be due to HDCP restrictions on the stream and the capabilities of the current device.',
1049+
...excludedHDPlaylists
1050+
);
1051+
1052+
// Clear the buffer before switching playlists, since it may already contain unplayable segments
1053+
this.playlistController_.fastQualityChange_();
10291054
}
10301055
});
10311056

test/videojs-http-streaming.test.js

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4278,11 +4278,20 @@ QUnit.test('configures eme for HLS on source buffer creation', function(assert)
42784278
});
42794279

42804280
QUnit.test('eme handles keystatuschange where status is output-restricted', function(assert) {
4281+
const originalWarn = videojs.log.warn;
4282+
let warning = '';
4283+
let qualitySwitches = 0;
4284+
4285+
videojs.log.warn = (...text) => {
4286+
warning += [...text].join('');
4287+
};
4288+
42814289
this.player.eme = {
42824290
options: {
42834291
previousSetting: 1
42844292
}
42854293
};
4294+
42864295
this.player.src({
42874296
src: 'manifest/main.m3u8',
42884297
type: 'application/x-mpegURL',
@@ -4295,39 +4304,64 @@ QUnit.test('eme handles keystatuschange where status is output-restricted', func
42954304

42964305
this.clock.tick(1);
42974306

4298-
const media = {
4299-
attributes: {
4300-
CODECS: 'avc1.420015, mp4a.40.2c'
4307+
const playlists = [
4308+
{
4309+
attributes: {
4310+
RESOLUTION: {
4311+
width: 1280,
4312+
height: 720
4313+
}
4314+
}
43014315
},
4302-
contentProtection: {
4303-
keySystem1: {
4304-
pssh: 'test'
4316+
{
4317+
attributes: {
4318+
RESOLUTION: {
4319+
width: 1920,
4320+
height: 1080
4321+
}
4322+
}
4323+
},
4324+
{
4325+
attributes: {
4326+
RESOLUTION: {
4327+
width: 848,
4328+
height: 480
4329+
}
43054330
}
43064331
}
4307-
};
4332+
];
43084333

43094334
this.player.tech_.vhs.playlists = {
4310-
main: { playlists: [media] },
4311-
media: () => media
4335+
main: { playlists },
4336+
media: () => playlists[0]
43124337
};
43134338

4314-
const excludes = [];
4339+
this.player.tech_.vhs.playlistController_.main = () => {
4340+
return {
4341+
playlists
4342+
};
4343+
};
43154344

4316-
this.player.tech_.vhs.playlistController_.excludePlaylist = (exclude) => {
4317-
excludes.push(exclude);
4345+
this.player.tech_.vhs.playlistController_.fastQualityChange_ = () => {
4346+
qualitySwitches++;
43184347
};
43194348

43204349
this.player.tech_.vhs.playlistController_.sourceUpdater_.trigger('createdsourcebuffers');
43214350
this.player.tech_.trigger({type: 'keystatuschange', status: 'output-restricted'});
43224351

4323-
assert.deepEqual(excludes, [{
4324-
playlistExclusionDuration: Infinity,
4325-
error: {
4326-
message: 'DRM keystatus changed to output-restricted. Playlist will fail to play. ' +
4327-
'Check for HDCP content.'
4328-
},
4329-
playlistToExclude: undefined
4330-
}], 'excluded playlist');
4352+
assert.equal(playlists[0].excludeUntil, Infinity, 'first HD playlist excluded');
4353+
assert.equal(playlists[1].excludeUntil, Infinity, 'second HD playlist excluded');
4354+
assert.equal(playlists[2].excludeUntil, undefined, 'non-HD playlist not excluded');
4355+
assert.equal(qualitySwitches, 1, 'fastQualityChange_ called once');
4356+
assert.equal(
4357+
warning,
4358+
'DRM keystatus changed to "output-restricted." Removing the following HD playlists ' +
4359+
'that will most likely fail to play and clearing the buffer. ' +
4360+
'This may be due to HDCP restrictions on the stream and the capabilities of the current device.' +
4361+
[playlists[0], playlists[1]].join('')
4362+
);
4363+
4364+
videojs.log.warn = originalWarn;
43314365
});
43324366

43334367
QUnit.test('eme handles keystatuschange where status is usable', function(assert) {

0 commit comments

Comments
 (0)