Skip to content

Commit a20bf0e

Browse files
committed
Fix delta updates with discontinuity tags (v1.5.x patch)
Fixes #6949
1 parent fed1d64 commit a20bf0e

File tree

2 files changed

+505
-38
lines changed

2 files changed

+505
-38
lines changed

src/utils/level-helper.ts

+37-38
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import { LevelDetails } from '../loader/level-details';
88
import type { Level } from '../types/level';
99
import { DateRange } from '../loader/date-range';
1010

11-
type FragmentIntersection = (oldFrag: Fragment, newFrag: Fragment) => void;
11+
type FragmentIntersection = (
12+
oldFrag: Fragment,
13+
newFrag: Fragment,
14+
newFragIndex: number,
15+
newFragments: Fragment[],
16+
) => void;
1217
type PartIntersection = (oldPart: Part, newPart: Part) => void;
1318

1419
export function updatePTS(
@@ -106,7 +111,7 @@ export function updateFragPTSDTS(
106111
if (!details || sn < details.startSN || sn > details.endSN) {
107112
return 0;
108113
}
109-
let i;
114+
let i: number;
110115
const fragIdx = sn - details.startSN;
111116
const fragments = details.fragments;
112117
// update frag reference in fragments array
@@ -152,18 +157,19 @@ export function mergeDetails(
152157
delete oldDetails.fragmentHint.endPTS;
153158
}
154159
// check if old/new playlists have fragments in common
155-
// loop through overlapping SN and update startPTS , cc, and duration if any found
156-
let ccOffset = 0;
157-
let PTSFrag;
160+
// loop through overlapping SN and update startPTS, cc, and duration if any found
161+
let PTSFrag: Fragment | undefined;
158162
mapFragmentIntersection(
159163
oldDetails,
160164
newDetails,
161-
(oldFrag: Fragment, newFrag: Fragment) => {
162-
if (oldFrag.relurl) {
163-
// Do not compare CC if the old fragment has no url. This is a level.fragmentHint used by LL-HLS parts.
164-
// It maybe be off by 1 if it was created before any parts or discontinuity tags were appended to the end
165-
// of the playlist.
166-
ccOffset = oldFrag.cc - newFrag.cc;
165+
(oldFrag, newFrag, newFragIndex, newFragments) => {
166+
if (newDetails.skippedSegments) {
167+
if (newFrag.cc !== oldFrag.cc) {
168+
const ccOffset = oldFrag.cc - newFrag.cc;
169+
for (let i = newFragIndex; i < newFragments.length; i++) {
170+
newFragments[i].cc += ccOffset;
171+
}
172+
}
167173
}
168174
if (
169175
Number.isFinite(oldFrag.startPTS) &&
@@ -196,10 +202,11 @@ export function mergeDetails(
196202
},
197203
);
198204

205+
const newFragments = newDetails.fragments;
199206
if (currentInitSegment) {
200207
const fragmentsToCheck = newDetails.fragmentHint
201-
? newDetails.fragments.concat(newDetails.fragmentHint)
202-
: newDetails.fragments;
208+
? newFragments.concat(newDetails.fragmentHint)
209+
: newFragments;
203210
fragmentsToCheck.forEach((frag) => {
204211
if (
205212
frag &&
@@ -212,34 +219,26 @@ export function mergeDetails(
212219
}
213220

214221
if (newDetails.skippedSegments) {
215-
newDetails.deltaUpdateFailed = newDetails.fragments.some((frag) => !frag);
222+
newDetails.deltaUpdateFailed = newFragments.some((frag) => !frag);
216223
if (newDetails.deltaUpdateFailed) {
217224
logger.warn(
218225
'[level-helper] Previous playlist missing segments skipped in delta playlist',
219226
);
220227
for (let i = newDetails.skippedSegments; i--; ) {
221-
newDetails.fragments.shift();
228+
newFragments.shift();
229+
}
230+
newDetails.startSN = newFragments[0].sn as number;
231+
} else {
232+
if (newDetails.canSkipDateRanges) {
233+
newDetails.dateRanges = mergeDateRanges(
234+
oldDetails.dateRanges,
235+
newDetails.dateRanges,
236+
newDetails.recentlyRemovedDateranges,
237+
);
222238
}
223-
newDetails.startSN = newDetails.fragments[0].sn as number;
224-
newDetails.startCC = newDetails.fragments[0].cc;
225-
} else if (newDetails.canSkipDateRanges) {
226-
newDetails.dateRanges = mergeDateRanges(
227-
oldDetails.dateRanges,
228-
newDetails.dateRanges,
229-
newDetails.recentlyRemovedDateranges,
230-
);
231-
}
232-
}
233-
234-
const newFragments = newDetails.fragments;
235-
if (ccOffset) {
236-
logger.warn('discontinuity sliding from playlist, take drift into account');
237-
for (let i = 0; i < newFragments.length; i++) {
238-
newFragments[i].cc += ccOffset;
239239
}
240-
}
241-
if (newDetails.skippedSegments) {
242240
newDetails.startCC = newDetails.fragments[0].cc;
241+
newDetails.endCC = newFragments[newFragments.length - 1].cc;
243242
}
244243

245244
// Merge parts
@@ -257,10 +256,10 @@ export function mergeDetails(
257256
updateFragPTSDTS(
258257
newDetails,
259258
PTSFrag,
260-
PTSFrag.startPTS,
261-
PTSFrag.endPTS,
262-
PTSFrag.startDTS,
263-
PTSFrag.endDTS,
259+
PTSFrag.startPTS as number,
260+
PTSFrag.endPTS as number,
261+
PTSFrag.startDTS as number,
262+
PTSFrag.endDTS as number,
264263
);
265264
} else {
266265
// ensure that delta is within oldFragments range
@@ -371,7 +370,7 @@ export function mapFragmentIntersection(
371370
newFrag = newDetails.fragments[i] = oldFrag;
372371
}
373372
if (oldFrag && newFrag) {
374-
intersectionFn(oldFrag, newFrag);
373+
intersectionFn(oldFrag, newFrag, i, newFrags);
375374
}
376375
}
377376
}

0 commit comments

Comments
 (0)