Skip to content

Commit 23bbf84

Browse files
authored
fix: output-restricted event handling for unplayable streams (#1305)
1 parent 97e02fb commit 23bbf84

File tree

2 files changed

+88
-23
lines changed

2 files changed

+88
-23
lines changed

src/videojs-http-streaming.js

+34-6
Original file line numberDiff line numberDiff line change
@@ -1061,12 +1061,40 @@ class VhsHandler extends Component {
10611061
});
10621062

10631063
this.player_.tech_.on('keystatuschange', (e) => {
1064-
if (e.status === 'output-restricted') {
1065-
this.masterPlaylistController_.blacklistCurrentPlaylist({
1066-
playlist: this.masterPlaylistController_.media(),
1067-
message: `DRM keystatus changed to ${e.status}. Playlist will fail to play. Check for HDCP content.`,
1068-
blacklistDuration: Infinity
1069-
});
1064+
if (e.status !== 'output-restricted') {
1065+
return;
1066+
}
1067+
1068+
const masterPlaylist = this.masterPlaylistController_.master();
1069+
1070+
if (!masterPlaylist || !masterPlaylist.playlists) {
1071+
return;
1072+
}
1073+
1074+
const excludedHDPlaylists = [];
1075+
1076+
// Assume all HD streams are unplayable and exclude them from ABR selection
1077+
masterPlaylist.playlists.forEach(playlist => {
1078+
if (playlist && playlist.attributes && playlist.attributes.RESOLUTION &&
1079+
playlist.attributes.RESOLUTION.height >= 720) {
1080+
if (!playlist.excludeUntil || playlist.excludeUntil < Infinity) {
1081+
1082+
playlist.excludeUntil = Infinity;
1083+
excludedHDPlaylists.push(playlist);
1084+
}
1085+
}
1086+
});
1087+
1088+
if (excludedHDPlaylists.length) {
1089+
videojs.log.warn(
1090+
'DRM keystatus changed to "output-restricted." Removing the following HD playlists ' +
1091+
'that will most likely fail to play and clearing the buffer. ' +
1092+
'This may be due to HDCP restrictions on the stream and the capabilities of the current device.',
1093+
...excludedHDPlaylists
1094+
);
1095+
1096+
// Clear the buffer before switching playlists, since it may already contain unplayable segments
1097+
this.masterPlaylistController_.fastQualityChange_();
10701098
}
10711099
});
10721100

test/videojs-http-streaming.test.js

+54-17
Original file line numberDiff line numberDiff line change
@@ -4618,11 +4618,20 @@ QUnit.test('configures eme for HLS on source buffer creation', function(assert)
46184618
});
46194619

46204620
QUnit.test('eme handles keystatuschange where status is output-restricted', function(assert) {
4621+
const originalWarn = videojs.log.warn;
4622+
let warning = '';
4623+
let qualitySwitches = 0;
4624+
4625+
videojs.log.warn = (...text) => {
4626+
warning += [...text].join('');
4627+
};
4628+
46214629
this.player.eme = {
46224630
options: {
46234631
previousSetting: 1
46244632
}
46254633
};
4634+
46264635
this.player.src({
46274636
src: 'manifest/master.m3u8',
46284637
type: 'application/x-mpegURL',
@@ -4635,36 +4644,64 @@ QUnit.test('eme handles keystatuschange where status is output-restricted', func
46354644

46364645
this.clock.tick(1);
46374646

4638-
const media = {
4639-
attributes: {
4640-
CODECS: 'avc1.420015, mp4a.40.2c'
4647+
const playlists = [
4648+
{
4649+
attributes: {
4650+
RESOLUTION: {
4651+
width: 1280,
4652+
height: 720
4653+
}
4654+
}
46414655
},
4642-
contentProtection: {
4643-
keySystem1: {
4644-
pssh: 'test'
4656+
{
4657+
attributes: {
4658+
RESOLUTION: {
4659+
width: 1920,
4660+
height: 1080
4661+
}
4662+
}
4663+
},
4664+
{
4665+
attributes: {
4666+
RESOLUTION: {
4667+
width: 848,
4668+
height: 480
4669+
}
46454670
}
46464671
}
4647-
};
4672+
];
46484673

46494674
this.player.tech_.vhs.playlists = {
4650-
master: { playlists: [media] },
4651-
media: () => media
4675+
master: { playlists },
4676+
media: () => playlists[0]
46524677
};
46534678

4654-
const excludes = [];
4679+
this.player.tech_.vhs.masterPlaylistController_.master = () => {
4680+
return {
4681+
playlists
4682+
};
4683+
};
46554684

4656-
this.player.tech_.vhs.masterPlaylistController_.blacklistCurrentPlaylist = (exclude) => {
4657-
excludes.push(exclude);
4685+
this.player.tech_.vhs.masterPlaylistController_.fastQualityChange_ = () => {
4686+
qualitySwitches++;
46584687
};
46594688

46604689
this.player.tech_.vhs.masterPlaylistController_.sourceUpdater_.trigger('createdsourcebuffers');
46614690
this.player.tech_.trigger({type: 'keystatuschange', status: 'output-restricted'});
46624691

4663-
assert.deepEqual(excludes, [{
4664-
blacklistDuration: Infinity,
4665-
message: 'DRM keystatus changed to output-restricted. Playlist will fail to play. Check for HDCP content.',
4666-
playlist: undefined
4667-
}], 'excluded playlist');
4692+
assert.equal(playlists[0].excludeUntil, Infinity, 'first HD playlist excluded');
4693+
assert.equal(playlists[1].excludeUntil, Infinity, 'second HD playlist excluded');
4694+
assert.equal(playlists[2].excludeUntil, undefined, 'non-HD playlist not excluded');
4695+
assert.equal(qualitySwitches, 1, 'fastQualityChange_ called once');
4696+
assert.equal(
4697+
warning,
4698+
'DRM keystatus changed to "output-restricted." Removing the following HD playlists ' +
4699+
'that will most likely fail to play and clearing the buffer. ' +
4700+
'This may be due to HDCP restrictions on the stream and the capabilities of the current device.' +
4701+
[playlists[0], playlists[1]].join('')
4702+
);
4703+
4704+
videojs.log.warn = originalWarn;
46684705
});
46694706

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

0 commit comments

Comments
 (0)