Skip to content

Commit aa9dfbd

Browse files
dzianis-dashkevichDzianis Dashkevich
andauthored
fix: CMAF HLS. Source buffer change type is called with wrong codecs sometimes when append segment without init data because of a race condition. (#1374)
* Get Codecs: Always use playlist for current pending segment instead of currently loaded playlist. * fix eslint errors * Clear active init segment id during reset everything --------- Co-authored-by: Dzianis Dashkevich <ddashkevich@brightcove.com>
1 parent 59d98df commit aa9dfbd

File tree

3 files changed

+54
-7
lines changed

3 files changed

+54
-7
lines changed

src/master-playlist-controller.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,9 +1725,11 @@ export class MasterPlaylistController extends videojs.EventTarget {
17251725
audio: this.audioSegmentLoader_.getCurrentMediaInfo_() || {}
17261726
};
17271727

1728+
const playlist = this.mainSegmentLoader_.getPendingSegmentPlaylist() || this.media();
1729+
17281730
// set "main" media equal to video
17291731
media.video = media.main;
1730-
const playlistCodecs = codecsForPlaylist(this.master(), this.media());
1732+
const playlistCodecs = codecsForPlaylist(this.master(), playlist);
17311733
const codecs = {};
17321734
const usingAudioLoader = !!this.mediaTypes_.AUDIO.activePlaylistLoader;
17331735

@@ -1748,7 +1750,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
17481750
// no codecs, no playback.
17491751
if (!codecs.audio && !codecs.video) {
17501752
this.blacklistCurrentPlaylist({
1751-
playlist: this.media(),
1753+
playlist,
17521754
message: 'Could not determine codecs for playlist.',
17531755
blacklistDuration: Infinity
17541756
});
@@ -1773,13 +1775,13 @@ export class MasterPlaylistController extends videojs.EventTarget {
17731775
}
17741776
});
17751777

1776-
if (usingAudioLoader && unsupportedAudio && this.media().attributes.AUDIO) {
1777-
const audioGroup = this.media().attributes.AUDIO;
1778+
if (usingAudioLoader && unsupportedAudio && playlist.attributes.AUDIO) {
1779+
const audioGroup = playlist.attributes.AUDIO;
17781780

17791781
this.master().playlists.forEach(variant => {
17801782
const variantAudioGroup = variant.attributes && variant.attributes.AUDIO;
17811783

1782-
if (variantAudioGroup === audioGroup && variant !== this.media()) {
1784+
if (variantAudioGroup === audioGroup && variant !== playlist) {
17831785
variant.excludeUntil = Infinity;
17841786
}
17851787
});
@@ -1800,7 +1802,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
18001802
}, '') + '.';
18011803

18021804
this.blacklistCurrentPlaylist({
1803-
playlist: this.media(),
1805+
playlist,
18041806
internal: true,
18051807
message,
18061808
blacklistDuration: Infinity
@@ -1825,7 +1827,7 @@ export class MasterPlaylistController extends videojs.EventTarget {
18251827

18261828
if (switchMessages.length) {
18271829
this.blacklistCurrentPlaylist({
1828-
playlist: this.media(),
1830+
playlist,
18291831
message: `Codec switching not supported: ${switchMessages.join(', ')}.`,
18301832
blacklistDuration: Infinity,
18311833
internal: true

src/segment-loader.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,7 @@ export default class SegmentLoader extends videojs.EventTarget {
11621162
*/
11631163
resetEverything(done) {
11641164
this.ended_ = false;
1165+
this.activeInitSegmentId_ = null;
11651166
this.appendInitSegment_ = {
11661167
audio: true,
11671168
video: true
@@ -1982,6 +1983,10 @@ export default class SegmentLoader extends videojs.EventTarget {
19821983
return this.getCurrentMediaInfo_(segmentInfo) || this.startingMediaInfo_;
19831984
}
19841985

1986+
getPendingSegmentPlaylist() {
1987+
return this.pendingSegment_ ? this.pendingSegment_.playlist : null;
1988+
}
1989+
19851990
hasEnoughInfoToAppend_() {
19861991
if (!this.sourceUpdater_.ready()) {
19871992
return false;

test/master-playlist-controller.test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5092,6 +5092,25 @@ QUnit.test('playlist codecs take priority over others', function(assert) {
50925092
assert.deepEqual(codecs, {video: 'avc1.4b400d', audio: 'mp4a.40.20'}, 'codecs returned');
50935093
});
50945094

5095+
QUnit.test('Current pending segment\'s playlist codecs take priority over others', function(assert) {
5096+
this.contentSetup({
5097+
mainStartingMedia: {videoCodec: 'avc1.4c400d', hasVideo: true, hasAudio: false},
5098+
audioStartingMedia: {audioCodec: 'mp4a.40.5', hasVideo: false, hasAudio: true},
5099+
mainPlaylist: {attributes: {CODECS: 'avc1.4b400d', AUDIO: 'low-quality'}},
5100+
audioPlaylist: {attributes: {CODECS: 'mp4a.40.20'}}
5101+
});
5102+
5103+
const originalGetPendingSegmentPlaylist = this.mpc.mainSegmentLoader_.getPendingSegmentPlaylist.bind(this.mpc.mainSegmentLoader_);
5104+
5105+
this.mpc.mainSegmentLoader_.getPendingSegmentPlaylist = () => ({attributes: {CODECS: 'avc1.64001f', AUDIO: 'low-quality'}});
5106+
5107+
const codecs = this.mpc.getCodecsOrExclude_();
5108+
5109+
assert.deepEqual(this.blacklists, [], 'did not blacklist anything');
5110+
assert.deepEqual(codecs, {video: 'avc1.64001f', audio: 'mp4a.40.20'}, 'codecs returned');
5111+
this.mpc.mainSegmentLoader_.getPendingSegmentPlaylist = originalGetPendingSegmentPlaylist;
5112+
});
5113+
50955114
QUnit.test('uses default codecs if no codecs are found', function(assert) {
50965115
this.contentSetup({
50975116
mainStartingMedia: {hasVideo: true, hasAudio: false},
@@ -5123,6 +5142,27 @@ QUnit.test('excludes playlist without detected audio/video', function(assert) {
51235142
assert.deepEqual(codecs, void 0, 'no codecs returned');
51245143
});
51255144

5145+
QUnit.test('excludes current pending segment\'s playlist without detected audio/video', function(assert) {
5146+
this.contentSetup({
5147+
mainStartingMedia: {},
5148+
audioStartingMedia: {},
5149+
mainPlaylist: {attributes: {}}
5150+
});
5151+
5152+
const originalGetPendingSegmentPlaylist = this.mpc.mainSegmentLoader_.getPendingSegmentPlaylist.bind(this.mpc.mainSegmentLoader_);
5153+
5154+
this.mpc.mainSegmentLoader_.getPendingSegmentPlaylist = () => ({attributes: {CODECS: ''}});
5155+
const codecs = this.mpc.getCodecsOrExclude_();
5156+
5157+
assert.deepEqual(this.blacklists, [{
5158+
blacklistDuration: Infinity,
5159+
message: 'Could not determine codecs for playlist.',
5160+
playlist: {attributes: {CODECS: ''}}
5161+
}], 'blacklisted playlist');
5162+
assert.deepEqual(codecs, void 0, 'no codecs returned');
5163+
this.mpc.mainSegmentLoader_.getPendingSegmentPlaylist = originalGetPendingSegmentPlaylist;
5164+
});
5165+
51265166
QUnit.test('excludes unsupported muxer codecs for ts', function(assert) {
51275167
this.contentSetup({
51285168
mainStartingMedia: {

0 commit comments

Comments
 (0)