Skip to content

Commit

Permalink
Only allow large gaps to be skipped if start gap or all fragments in …
Browse files Browse the repository at this point in the history
…range are partial

Fixes #5360
  • Loading branch information
robwalch committed Apr 5, 2023
1 parent dc67742 commit 25225c3
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 10 deletions.
4 changes: 3 additions & 1 deletion api-extractor/report/hls.js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ export class BaseSegment {
//
// @public (undocumented)
export class BaseStreamController extends TaskLoop implements NetworkComponentAPI {
constructor(hls: Hls, fragmentTracker: FragmentTracker, keyLoader: KeyLoader, logPrefix: string);
constructor(hls: Hls, fragmentTracker: FragmentTracker, keyLoader: KeyLoader, logPrefix: string, playlistType: PlaylistLevelType);
// (undocumented)
protected afterBufferFlushed(media: Bufferable, bufferType: SourceBufferName, playlistType: PlaylistLevelType): void;
// (undocumented)
Expand Down Expand Up @@ -412,6 +412,8 @@ export class BaseStreamController extends TaskLoop implements NetworkComponentAP
// (undocumented)
protected onvseeking: EventListener | null;
// (undocumented)
protected playlistType: PlaylistLevelType;
// (undocumented)
protected recoverWorkerError(data: ErrorData): void;
// (undocumented)
protected reduceLengthAndFlushBuffer(data: ErrorData): boolean;
Expand Down
8 changes: 7 additions & 1 deletion src/controller/audio-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,13 @@ class AudioStreamController
fragmentTracker: FragmentTracker,
keyLoader: KeyLoader
) {
super(hls, fragmentTracker, keyLoader, '[audio-stream-controller]');
super(
hls,
fragmentTracker,
keyLoader,
'[audio-stream-controller]',
PlaylistLevelType.AUDIO
);
this._registerListeners();
}

Expand Down
15 changes: 14 additions & 1 deletion src/controller/base-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default class BaseStreamController
protected fragmentTracker: FragmentTracker;
protected transmuxer: TransmuxerInterface | null = null;
protected _state: string = State.STOPPED;
protected playlistType: PlaylistLevelType;
protected media: HTMLMediaElement | null = null;
protected mediaBuffer: Bufferable | null = null;
protected config: HlsConfig;
Expand Down Expand Up @@ -107,9 +108,11 @@ export default class BaseStreamController
hls: Hls,
fragmentTracker: FragmentTracker,
keyLoader: KeyLoader,
logPrefix: string
logPrefix: string,
playlistType: PlaylistLevelType
) {
super();
this.playlistType = playlistType;
this.logPrefix = logPrefix;
this.log = logger.log.bind(logger, `${logPrefix}:`);
this.warn = logger.warn.bind(logger, `${logPrefix}:`);
Expand Down Expand Up @@ -270,6 +273,16 @@ export default class BaseStreamController
}

if (media) {
// Remove gap fragments
if (this.lastCurrentTime > currentTime) {
this.fragmentTracker.removeFragmentsInRange(
currentTime,
this.lastCurrentTime,
this.playlistType,
true
);
}

this.lastCurrentTime = currentTime;
}

Expand Down
5 changes: 3 additions & 2 deletions src/controller/fragment-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export class FragmentTracker implements ComponentAPI {
}
}

public fragBuffered(frag: Fragment, force?: boolean) {
public fragBuffered(frag: Fragment, force?: true) {
const fragKey = getFragmentKey(frag);
let fragmentEntity = this.fragments[fragKey];
if (!fragmentEntity && force) {
Expand Down Expand Up @@ -447,7 +447,8 @@ export class FragmentTracker implements ComponentAPI {
public removeFragmentsInRange(
start: number,
end: number,
playlistType: PlaylistLevelType
playlistType: PlaylistLevelType,
withGap?: true
) {
Object.keys(this.fragments).forEach((key) => {
const fragmentEntity = this.fragments[key];
Expand Down
42 changes: 41 additions & 1 deletion src/controller/gap-controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { BufferInfo } from '../utils/buffer-helper';
import { BufferHelper } from '../utils/buffer-helper';
import { ErrorTypes, ErrorDetails } from '../errors';
import { PlaylistLevelType } from '../types/loader';
import { Events } from '../events';
import { logger } from '../utils/logger';
import type Hls from '../hls';
Expand Down Expand Up @@ -256,7 +257,46 @@ export default class GapController {
const bufferStarved = bufferInfo.len <= config.maxBufferHole;
const waiting =
bufferInfo.len > 0 && bufferInfo.len < 1 && media.readyState < 3;
if (currentTime < startTime && (bufferStarved || waiting)) {
const gapLength = startTime - currentTime;
if (gapLength > 0 && (bufferStarved || waiting)) {
// Only allow large gaps to be skipped if it is a start gap, or all fragments in skip range are partial
if (gapLength > config.maxBufferHole) {
const { fragmentTracker } = this;
let startGap = false;
if (currentTime === 0) {
const startFrag = fragmentTracker.getAppendedFrag(
0,
PlaylistLevelType.MAIN
);
if (startFrag && startTime < startFrag.end) {
startGap = true;
}
}
if (!startGap) {
const startProvisioned =
partial ||
fragmentTracker.getAppendedFrag(
currentTime,
PlaylistLevelType.MAIN
);
if (startProvisioned) {
let moreToLoad = false;
let pos = startProvisioned.end;
while (pos < startTime) {
const provisioned = fragmentTracker.getPartialFragment(pos);
if (provisioned) {
pos += provisioned.duration;
} else {
moreToLoad = true;
break;
}
}
if (moreToLoad) {
return 0;
}
}
}
}
const targetTime = Math.max(
startTime + SKIP_BUFFER_RANGE_START,
currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS
Expand Down
7 changes: 5 additions & 2 deletions src/controller/level-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,13 @@ export function updateFragPTSDTS(
endPTS = Math.max(endPTS, fragEndPts);
endDTS = Math.max(endDTS, frag.endDTS);
}
frag.duration = endPTS - startPTS;

const drift = startPTS - frag.start;
frag.start = frag.startPTS = startPTS;
if (frag.start !== 0) {
frag.start = startPTS;
}
frag.duration = endPTS - frag.start;
frag.startPTS = startPTS;
frag.maxStartPTS = maxStartPTS;
frag.startDTS = startDTS;
frag.endPTS = endPTS;
Expand Down
8 changes: 7 additions & 1 deletion src/controller/stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@ export default class StreamController
fragmentTracker: FragmentTracker,
keyLoader: KeyLoader
) {
super(hls, fragmentTracker, keyLoader, '[stream-controller]');
super(
hls,
fragmentTracker,
keyLoader,
'[stream-controller]',
PlaylistLevelType.MAIN
);
this._registerListeners();
}

Expand Down
8 changes: 7 additions & 1 deletion src/controller/subtitle-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ export class SubtitleStreamController
fragmentTracker: FragmentTracker,
keyLoader: KeyLoader
) {
super(hls, fragmentTracker, keyLoader, '[subtitle-stream-controller]');
super(
hls,
fragmentTracker,
keyLoader,
'[subtitle-stream-controller]',
PlaylistLevelType.SUBTITLE
);
this._registerListeners();
}

Expand Down

0 comments on commit 25225c3

Please sign in to comment.