Skip to content

Commit

Permalink
Fix handling of segments at the discontinuities that do not start wit…
Browse files Browse the repository at this point in the history
…h a keyframe

Fixes #5629

- Prevents backtracking on first segment in discontinuity
- Uses gap skipping to handle gap jumping prevent loop loading
  • Loading branch information
robwalch committed Jul 14, 2023
1 parent 9bbbdb6 commit b6af72f
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
32 changes: 23 additions & 9 deletions src/controller/stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1111,9 +1111,11 @@ export default class StreamController
}

// Avoid buffering if backtracking this fragment
const notFirstFragment = frag.sn !== details?.startSN;
if (video && remuxResult.independent !== false) {
if (details) {
if (video && details && frag.sn !== 'initSegment') {
const prevFrag = details.fragments[frag.sn - 1 - details.startSN];
const isFirstFragment = frag.sn === details.startSN;
const isFirstInDiscontinuity = !prevFrag || frag.cc > prevFrag.cc;
if (remuxResult.independent !== false) {
const { startPTS, endPTS, startDTS, endDTS } = video;
if (part) {
part.elementaryStreams[video.type] = {
Expand All @@ -1123,7 +1125,12 @@ export default class StreamController
endDTS,
};
} else {
if (video.firstKeyFrame && video.independent && chunkMeta.id === 1) {
if (
video.firstKeyFrame &&
video.independent &&
chunkMeta.id === 1 &&
!isFirstInDiscontinuity
) {
this.couldBacktrack = true;
}
if (video.dropped && video.independent) {
Expand All @@ -1137,11 +1144,15 @@ export default class StreamController
? video.firstKeyFramePTS
: startPTS;
if (
notFirstFragment &&
targetBufferTime < startTime - this.config.maxBufferHole
!isFirstFragment &&
targetBufferTime < startTime - this.config.maxBufferHole &&
!isFirstInDiscontinuity
) {
this.backtrack(frag);
return;
} else if (isFirstInDiscontinuity) {
// Mark segment with a gap to avoid loop loading
frag.gap = true;
}
// Set video stream start to fragment start so that truncated samples do not distort the timeline, and mark it partial
frag.setElementaryStreamInfo(
Expand All @@ -1165,10 +1176,13 @@ export default class StreamController
this.backtrackFragment = frag;
}
this.bufferFragmentData(video, frag, part, chunkMeta);
} else if (isFirstFragment || isFirstInDiscontinuity) {
// Mark segment with a gap to avoid loop loading
frag.gap = true;
} else {
this.backtrack(frag);
return;
}
} else if (notFirstFragment && remuxResult.independent === false) {
this.backtrack(frag);
return;
}

if (audio) {
Expand Down
5 changes: 4 additions & 1 deletion src/loader/fragment-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ export default class FragmentLoader {
if (this.loader) {
this.loader.destroy();
}
if (frag.gap) {
if (frag.gap && frag.tagList.some((tags) => tags[0] === 'GAP')) {
reject(createGapLoadError(frag));
return;
} else {
// Reset temporary treatment as GAP tag
frag.gap = false;
}
const loader =
(this.loader =
Expand Down

0 comments on commit b6af72f

Please sign in to comment.