Skip to content

Commit

Permalink
Force media capabilities check for HEVC to avoid failure on Windows (#…
Browse files Browse the repository at this point in the history
…6849)

Fix removeLevel side-effects when removing current level or changing index of loading level
Fixes failed test results: https://github.com/video-dev/hls.js/actions/runs/11844914912/job/33012913783?pr=6845
  • Loading branch information
robwalch authored Nov 18, 2024
1 parent 0ecc0fa commit 7db2f52
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 15 deletions.
10 changes: 10 additions & 0 deletions api-extractor/report/hls.js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3249,6 +3249,8 @@ export interface LevelLoadedData {
// (undocumented)
level: number;
// (undocumented)
levelInfo: Level;
// (undocumented)
networkDetails: any;
// (undocumented)
stats: LoaderStats;
Expand All @@ -3265,6 +3267,8 @@ export interface LevelLoadingData {
// (undocumented)
level: number;
// (undocumented)
levelInfo: Level;
// (undocumented)
pathwayId: string | undefined;
// (undocumented)
url: string;
Expand Down Expand Up @@ -4153,6 +4157,8 @@ export interface PlaylistLoaderContext extends LoaderContext {
// (undocumented)
levelDetails?: LevelDetails;
// (undocumented)
levelOrTrack: Level | MediaPlaylist | null;
// (undocumented)
pathwayId?: string;
// (undocumented)
type: PlaylistContextType;
Expand Down Expand Up @@ -4638,6 +4644,8 @@ export interface TrackLoadedData {
networkDetails: any;
// (undocumented)
stats: LoaderStats;
// (undocumented)
track: MediaPlaylist;
}

// Warning: (ae-missing-release-tag) "TrackLoadingData" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand All @@ -4651,6 +4659,8 @@ export interface TrackLoadingData {
// (undocumented)
id: number;
// (undocumented)
track: MediaPlaylist;
// (undocumented)
url: string;
}

Expand Down
8 changes: 6 additions & 2 deletions src/controller/abr-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -795,14 +795,15 @@ class AbrController extends Logger implements AbrComponentAPI {
| undefined;
if (
typeof mediaCapabilities?.decodingInfo === 'function' &&
requiresMediaCapabilitiesDecodingInfo(
(requiresMediaCapabilitiesDecodingInfo(
levelInfo,
audioTracksByGroup,
currentVideoRange,
currentFrameRate,
currentBw,
audioPreference,
)
) ||
levelInfo.videoCodec?.substring(0, 4) === 'hvc1') // Force media capabilities check for HEVC to avoid failure on Windows
) {
levelInfo.supportedPromise = getMediaDecodingInfoPromise(
levelInfo,
Expand Down Expand Up @@ -831,6 +832,9 @@ class AbrController extends Logger implements AbrComponentAPI {
if (index > -1 && levels.length > 1) {
this.log(`Removing unsupported level ${index}`);
this.hls.removeLevel(index);
if (this.hls.loadLevel === -1) {
this.hls.nextLoadLevel = 0;
}
}
}
});
Expand Down
1 change: 1 addition & 0 deletions src/controller/audio-track-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ class AudioTrackController extends BasePlaylistController {
id,
groupId,
deliveryDirectives: hlsUrlParameters || null,
track: audioTrack,
});
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/controller/level-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ export default class LevelController extends BasePlaylistController {

protected onLevelLoaded(event: Events.LEVEL_LOADED, data: LevelLoadedData) {
const { level, details } = data;
const curLevel = this._levels[level];
const curLevel = data.levelInfo;

if (!curLevel) {
this.warn(`Invalid level index ${level}`);
Expand All @@ -612,7 +612,7 @@ export default class LevelController extends BasePlaylistController {
}

// only process level loaded events matching with expected level
if (level === this.currentLevelIndex) {
if (curLevel === this.currentLevel) {
// reset level load error counter on successful level loaded only if there is no issues with fragments
if (curLevel.fragmentError === 0) {
curLevel.loadError = 0;
Expand Down Expand Up @@ -665,6 +665,7 @@ export default class LevelController extends BasePlaylistController {
this.hls.trigger(Events.LEVEL_LOADING, {
url,
level: currentLevelIndex,
levelInfo: currentLevel,
pathwayId: currentLevel.attrs['PATHWAY-ID'],
id: 0, // Deprecated Level urlId
deliveryDirectives: hlsUrlParameters || null,
Expand Down
4 changes: 2 additions & 2 deletions src/controller/stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ export default class StreamController
if (!levels || this.state !== State.IDLE) {
return;
}
const level = levels[data.level];
const level = data.levelInfo;
if (
!level.details ||
(level.details.live && this.levelLastLoaded !== level) ||
Expand Down Expand Up @@ -674,7 +674,7 @@ export default class StreamController
}, cc [${newDetails.startCC}, ${newDetails.endCC}] duration:${duration}`,
);

const curLevel = levels[newLevelId];
const curLevel = data.levelInfo;
const fragCurrent = this.fragCurrent;
if (
fragCurrent &&
Expand Down
1 change: 1 addition & 0 deletions src/controller/subtitle-track-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ class SubtitleTrackController extends BasePlaylistController {
id,
groupId,
deliveryDirectives: hlsUrlParameters || null,
track: currentTrack,
});
}
}
Expand Down
46 changes: 38 additions & 8 deletions src/loader/playlist-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import type { NetworkComponentAPI } from '../types/component-api';
import type {
ErrorData,
LevelLoadingData,
LevelsUpdatedData,
ManifestLoadingData,
TrackLoadingData,
} from '../types/events';
import type { LevelParsed, VariableMap } from '../types/level';
import type { Level, LevelParsed, VariableMap } from '../types/level';
import type {
Loader,
LoaderCallbacks,
Expand All @@ -31,7 +32,7 @@ import type {
LoaderStats,
PlaylistLoaderContext,
} from '../types/loader';
import type { MediaAttributes } from '../types/media-playlist';
import type { MediaAttributes, MediaPlaylist } from '../types/media-playlist';

function mapContextToLevelType(
context: PlaylistLoaderContext,
Expand Down Expand Up @@ -86,6 +87,7 @@ class PlaylistLoader implements NetworkComponentAPI {
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
hls.on(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
hls.on(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
}

private unregisterListeners() {
Expand All @@ -94,6 +96,7 @@ class PlaylistLoader implements NetworkComponentAPI {
hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
hls.off(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
hls.off(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
}

/**
Expand All @@ -118,7 +121,7 @@ class PlaylistLoader implements NetworkComponentAPI {
return this.loaders[context.type];
}

private resetInternalLoader(contextType): void {
private resetInternalLoader(contextType: PlaylistContextType): void {
if (this.loaders[contextType]) {
delete this.loaders[contextType];
}
Expand All @@ -134,7 +137,7 @@ class PlaylistLoader implements NetworkComponentAPI {
loader.destroy();
}

this.resetInternalLoader(contextType);
this.resetInternalLoader(contextType as PlaylistContextType);
}
}

Expand All @@ -157,11 +160,12 @@ class PlaylistLoader implements NetworkComponentAPI {
type: PlaylistContextType.MANIFEST,
url,
deliveryDirectives: null,
levelOrTrack: null,
});
}

private onLevelLoading(event: Events.LEVEL_LOADING, data: LevelLoadingData) {
const { id, level, pathwayId, url, deliveryDirectives } = data;
const { id, level, pathwayId, url, deliveryDirectives, levelInfo } = data;
this.load({
id,
level,
Expand All @@ -170,14 +174,15 @@ class PlaylistLoader implements NetworkComponentAPI {
type: PlaylistContextType.LEVEL,
url,
deliveryDirectives,
levelOrTrack: levelInfo,
});
}

private onAudioTrackLoading(
event: Events.AUDIO_TRACK_LOADING,
data: TrackLoadingData,
) {
const { id, groupId, url, deliveryDirectives } = data;
const { id, groupId, url, deliveryDirectives, track } = data;
this.load({
id,
groupId,
Expand All @@ -186,14 +191,15 @@ class PlaylistLoader implements NetworkComponentAPI {
type: PlaylistContextType.AUDIO_TRACK,
url,
deliveryDirectives,
levelOrTrack: track,
});
}

private onSubtitleTrackLoading(
event: Events.SUBTITLE_TRACK_LOADING,
data: TrackLoadingData,
) {
const { id, groupId, url, deliveryDirectives } = data;
const { id, groupId, url, deliveryDirectives, track } = data;
this.load({
id,
groupId,
Expand All @@ -202,9 +208,30 @@ class PlaylistLoader implements NetworkComponentAPI {
type: PlaylistContextType.SUBTITLE_TRACK,
url,
deliveryDirectives,
levelOrTrack: track,
});
}

private onLevelsUpdated(
event: Events.LEVELS_UPDATED,
data: LevelsUpdatedData,
) {
// abort and delete loader of removed levels
const loader = this.loaders[PlaylistContextType.LEVEL];
if (loader) {
const context = loader.context;
if (
context &&
!data.levels.some(
(lvl) => lvl === (context as PlaylistLoaderContext).levelOrTrack,
)
) {
loader.abort();
delete this.loaders[PlaylistContextType.LEVEL];
}
}
}

private load(context: PlaylistLoaderContext): void {
const config = this.hls.config;

Expand All @@ -217,7 +244,7 @@ class PlaylistLoader implements NetworkComponentAPI {
if (
loaderContext &&
loaderContext.url === context.url &&
loaderContext.level === context.level
loaderContext.levelOrTrack === context.levelOrTrack
) {
// same URL can't overlap
this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
Expand Down Expand Up @@ -680,6 +707,7 @@ class PlaylistLoader implements NetworkComponentAPI {
case PlaylistContextType.LEVEL:
hls.trigger(Events.LEVEL_LOADED, {
details: levelDetails,
levelInfo: (context.levelOrTrack as Level) || hls.levels[0],
level: levelIndex || 0,
id: id || 0,
stats,
Expand All @@ -690,6 +718,7 @@ class PlaylistLoader implements NetworkComponentAPI {
case PlaylistContextType.AUDIO_TRACK:
hls.trigger(Events.AUDIO_TRACK_LOADED, {
details: levelDetails,
track: context.levelOrTrack as MediaPlaylist,
id: id || 0,
groupId: groupId || '',
stats,
Expand All @@ -700,6 +729,7 @@ class PlaylistLoader implements NetworkComponentAPI {
case PlaylistContextType.SUBTITLE_TRACK:
hls.trigger(Events.SUBTITLE_TRACK_LOADED, {
details: levelDetails,
track: context.levelOrTrack as MediaPlaylist,
id: id || 0,
groupId: groupId || '',
stats,
Expand Down
4 changes: 4 additions & 0 deletions src/types/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,15 @@ export interface LevelSwitchedData {
export interface TrackLoadingData {
id: number;
groupId: string;
track: MediaPlaylist;
url: string;
deliveryDirectives: HlsUrlParameters | null;
}

export interface LevelLoadingData {
id: number;
level: number;
levelInfo: Level;
pathwayId: string | undefined;
url: string;
deliveryDirectives: HlsUrlParameters | null;
Expand All @@ -207,12 +209,14 @@ export interface TrackLoadedData {
networkDetails: any;
stats: LoaderStats;
deliveryDirectives: HlsUrlParameters | null;
track: MediaPlaylist;
}

export interface LevelLoadedData {
details: LevelDetails;
id: number;
level: number;
levelInfo: Level;
networkDetails: any;
stats: LoaderStats;
deliveryDirectives: HlsUrlParameters | null;
Expand Down
5 changes: 4 additions & 1 deletion src/types/loader.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { LoaderConfig } from '../config';
import type { HlsUrlParameters } from './level';
import type { HlsUrlParameters, Level } from './level';
import type { MediaPlaylist } from './media-playlist';
import type { Fragment } from '../loader/fragment';
import type { Part } from '../loader/fragment';
import type { KeyLoaderInfo } from '../loader/key-loader';
Expand Down Expand Up @@ -191,4 +192,6 @@ export interface PlaylistLoaderContext extends LoaderContext {
levelDetails?: LevelDetails;
// Blocking playlist request delivery directives (or null id none were added to playlist url
deliveryDirectives: HlsUrlParameters | null;
// Reference to level or track object in hls.levels, hls.allAudioTracks, or hls.allSubtitleTracks (null when loading MVP)
levelOrTrack: Level | MediaPlaylist | null;
}
1 change: 1 addition & 0 deletions tests/unit/controller/audio-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ describe('AudioStreamController', function () {
},
targetduration: 100,
} as unknown as LevelDetails,
track: {} as any,
};

audioStreamController.levels = tracks;
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/controller/audio-track-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ describe('AudioTrackController', function () {
networkDetails: null,
stats: { loading: {} } as any,
deliveryDirectives: null,
track: {} as any,
});
expect(audioTrackController.tracksInGroup[0], 'tracksInGroup[0]')
.to.have.property('details')
Expand All @@ -299,6 +300,7 @@ describe('AudioTrackController', function () {
networkDetails: null,
stats: { loading: {} } as any,
deliveryDirectives: null,
track: {} as any,
});
expect(audioTrackController.tracksInGroup[1], 'tracksInGroup[1]')
.to.have.property('details')
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/controller/stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ describe('StreamController', function () {
networkDetails: {},
stats: new LoadStats(),
deliveryDirectives: null,
levelInfo: new Level({
name: '',
url: '',
attrs,
bitrate: 500000,
}),
});
expect(streamController['startPosition']).to.equal(130.5);
expect(streamController['nextLoadPosition']).to.equal(130.5);
Expand Down Expand Up @@ -174,6 +180,12 @@ describe('StreamController', function () {
networkDetails: {},
stats: new LoadStats(),
deliveryDirectives: null,
levelInfo: new Level({
name: '',
url: '',
attrs,
bitrate: 500000,
}),
});
expect(streamController['startPosition']).to.equal(18);
expect(streamController['nextLoadPosition']).to.equal(18);
Expand Down
Loading

0 comments on commit 7db2f52

Please sign in to comment.