mirror of
https://github.com/video-dev/hls.js.git
synced 2026-05-17 13:30:38 +00:00
Make part.gap writable and handle part muxing errors as gaps (#7814)
* Make part.gap writable and handle part muxing errors as gaps * Fix regression in part picking introduced in #7797 * Fix regression in fmp4 endPTS parsing introduced in #7807 * Fix handling of audio fragment parsing error prior to appending init-segment
This commit is contained in:
@@ -4517,7 +4517,7 @@ export class Part extends BaseSegment {
|
||||
// (undocumented)
|
||||
readonly fragOffset: number;
|
||||
// (undocumented)
|
||||
readonly gap: boolean;
|
||||
gap: boolean;
|
||||
// (undocumented)
|
||||
readonly independent: boolean;
|
||||
// (undocumented)
|
||||
|
||||
@@ -905,6 +905,9 @@ class AudioStreamController
|
||||
// If we are, subsequently check if the currently loading fragment (fragCurrent) has changed.
|
||||
if (this.fragContextChanged(frag) || !details) {
|
||||
this.fragmentTracker.removeFragment(frag);
|
||||
if (initSegment?.tracks) {
|
||||
this.resetTransmuxer();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1525,7 +1525,6 @@ export default class BaseStreamController
|
||||
if (frag.stats.retry > 1) {
|
||||
return true;
|
||||
}
|
||||
frag.stats.retry++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1664,7 +1663,7 @@ export default class BaseStreamController
|
||||
if (nextPart > -1 && targetBufferTime < part.start) {
|
||||
break;
|
||||
}
|
||||
const loaded = part.loaded;
|
||||
const loaded = part.loaded || part.gap;
|
||||
if (loaded) {
|
||||
nextPart = -1;
|
||||
} else if (
|
||||
@@ -1673,7 +1672,7 @@ export default class BaseStreamController
|
||||
) {
|
||||
nextPart = i;
|
||||
}
|
||||
contiguous = loaded;
|
||||
contiguous = loaded && !part.gap;
|
||||
}
|
||||
const part = partList[nextPart];
|
||||
if (part && part.fragment !== frag) {
|
||||
@@ -2016,7 +2015,7 @@ export default class BaseStreamController
|
||||
data.frag = context.frag;
|
||||
}
|
||||
}
|
||||
const frag = data.frag;
|
||||
const { frag, part } = data;
|
||||
// Handle frag error related to caller's filterType
|
||||
if (!frag || !this.levels || frag.type !== filterType) {
|
||||
return;
|
||||
@@ -2054,7 +2053,11 @@ export default class BaseStreamController
|
||||
!isUnusableKeyError(data)
|
||||
) {
|
||||
this.resetFragmentErrors(filterType);
|
||||
this.treatAsGap(frag);
|
||||
if (part) {
|
||||
part.gap = true;
|
||||
} else {
|
||||
this.treatAsGap(frag);
|
||||
}
|
||||
errorAction.resolved = true;
|
||||
} else if ((retry || noAlternate) && retryCount < retryConfig.maxNumRetry) {
|
||||
const offlineStatus = offlineHttpStatus(data.response?.code);
|
||||
|
||||
@@ -250,7 +250,7 @@ export class FragmentTracker implements ComponentAPI {
|
||||
const partial = isFragHint || streamInfo.partial === true;
|
||||
fragmentEntity.range[elementaryStream] = this.getBufferedTimes(
|
||||
frag,
|
||||
data.part,
|
||||
part,
|
||||
partial,
|
||||
timeRange,
|
||||
);
|
||||
|
||||
+15
-3
@@ -349,7 +349,7 @@ class TSDemuxer implements Demuxer {
|
||||
if (audioData && (pes = parsePES(audioData, this.logger))) {
|
||||
switch (audioTrack.segmentCodec) {
|
||||
case 'aac':
|
||||
this.parseAACPES(audioTrack, pes);
|
||||
this.parseAACPES(audioTrack, pes, chunkMeta);
|
||||
break;
|
||||
case 'mp3':
|
||||
this.parseMPEGPES(audioTrack, pes);
|
||||
@@ -421,6 +421,7 @@ class TSDemuxer implements Demuxer {
|
||||
this.observer,
|
||||
this.logger,
|
||||
this.config,
|
||||
chunkMeta,
|
||||
);
|
||||
|
||||
// only update track id if track PID found while parsing PMT
|
||||
@@ -478,6 +479,7 @@ class TSDemuxer implements Demuxer {
|
||||
new Error(
|
||||
`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`,
|
||||
),
|
||||
chunkMeta,
|
||||
undefined,
|
||||
this.logger,
|
||||
);
|
||||
@@ -560,7 +562,7 @@ class TSDemuxer implements Demuxer {
|
||||
if (audioData && (pes = parsePES(audioData, this.logger))) {
|
||||
switch (audioTrack.segmentCodec) {
|
||||
case 'aac':
|
||||
this.parseAACPES(audioTrack, pes);
|
||||
this.parseAACPES(audioTrack, pes, chunkMeta);
|
||||
break;
|
||||
case 'mp3':
|
||||
this.parseMPEGPES(audioTrack, pes);
|
||||
@@ -671,7 +673,11 @@ class TSDemuxer implements Demuxer {
|
||||
this.videoIntegrityChecker = null;
|
||||
}
|
||||
|
||||
private parseAACPES(track: DemuxedAudioTrack, pes: PES) {
|
||||
private parseAACPES(
|
||||
track: DemuxedAudioTrack,
|
||||
pes: PES,
|
||||
chunkMeta: ChunkMetadata,
|
||||
) {
|
||||
let startOffset = 0;
|
||||
const aacOverFlow = this.aacOverFlow;
|
||||
let data = pes.data;
|
||||
@@ -712,6 +718,7 @@ class TSDemuxer implements Demuxer {
|
||||
emitParsingError(
|
||||
this.observer,
|
||||
new Error(reason),
|
||||
chunkMeta,
|
||||
recoverable,
|
||||
this.logger,
|
||||
);
|
||||
@@ -922,6 +929,7 @@ function parsePMT(
|
||||
observer: HlsEventEmitter,
|
||||
logger: ILogger,
|
||||
config: HlsConfig,
|
||||
chunkMeta: ChunkMetadata,
|
||||
) {
|
||||
const result = {
|
||||
audioPid: -1,
|
||||
@@ -1062,6 +1070,7 @@ function parsePMT(
|
||||
emitParsingError(
|
||||
observer,
|
||||
new Error('Unsupported EC-3 in M2TS found'),
|
||||
chunkMeta,
|
||||
undefined,
|
||||
logger,
|
||||
);
|
||||
@@ -1078,6 +1087,7 @@ function parsePMT(
|
||||
emitParsingError(
|
||||
observer,
|
||||
new Error('Unsupported HEVC in M2TS found'),
|
||||
chunkMeta,
|
||||
undefined,
|
||||
logger,
|
||||
);
|
||||
@@ -1099,6 +1109,7 @@ function parsePMT(
|
||||
function emitParsingError(
|
||||
observer: HlsEventEmitter,
|
||||
error: Error,
|
||||
chunkMeta: ChunkMetadata,
|
||||
levelRetry: boolean | undefined,
|
||||
logger: ILogger,
|
||||
) {
|
||||
@@ -1108,6 +1119,7 @@ function emitParsingError(
|
||||
details: ErrorDetails.FRAG_PARSING_ERROR,
|
||||
fatal: false,
|
||||
levelRetry,
|
||||
chunkMeta,
|
||||
error,
|
||||
reason: error.message,
|
||||
});
|
||||
|
||||
@@ -433,11 +433,11 @@ export class Fragment extends BaseSegment {
|
||||
export class Part extends BaseSegment {
|
||||
public readonly fragOffset: number = 0;
|
||||
public readonly duration: number = 0;
|
||||
public readonly gap: boolean = false;
|
||||
public readonly independent: boolean = false;
|
||||
public readonly relurl: string;
|
||||
public readonly fragment: MediaFragment;
|
||||
public readonly index: number;
|
||||
public gap: boolean = false;
|
||||
|
||||
constructor(
|
||||
partAttrs: AttrList,
|
||||
|
||||
@@ -280,6 +280,7 @@ export default class MP4Remuxer extends Logger implements Remuxer {
|
||||
playlistType === PlaylistLevelType.AUDIO
|
||||
? videoTimeOffset
|
||||
: undefined,
|
||||
chunkMeta,
|
||||
);
|
||||
if (enoughVideoSamples) {
|
||||
const audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0;
|
||||
@@ -713,6 +714,7 @@ export default class MP4Remuxer extends Logger implements Remuxer {
|
||||
type: ErrorTypes.MUX_ERROR,
|
||||
details: ErrorDetails.REMUX_ALLOC_ERROR,
|
||||
fatal: false,
|
||||
chunkMeta,
|
||||
error: err,
|
||||
bytes: mdatSize,
|
||||
reason: `fail allocating video mdat ${mdatSize}`,
|
||||
@@ -932,7 +934,8 @@ export default class MP4Remuxer extends Logger implements Remuxer {
|
||||
timeOffset: number,
|
||||
contiguous: boolean,
|
||||
accurateTimeOffset: boolean,
|
||||
videoTimeOffset?: number,
|
||||
videoTimeOffset: number | undefined,
|
||||
chunkMeta: ChunkMetadata,
|
||||
): RemuxedTrack | undefined {
|
||||
const inputTimeScale: number = track.inputTimeScale;
|
||||
const mp4timeScale: number = track.samplerate
|
||||
@@ -1134,6 +1137,7 @@ export default class MP4Remuxer extends Logger implements Remuxer {
|
||||
type: ErrorTypes.MUX_ERROR,
|
||||
details: ErrorDetails.REMUX_ALLOC_ERROR,
|
||||
fatal: false,
|
||||
chunkMeta,
|
||||
error: err,
|
||||
bytes: mdatSize,
|
||||
reason: `fail allocating audio mdat ${mdatSize}`,
|
||||
|
||||
@@ -8,9 +8,9 @@ import { getCodecCompatibleName } from '../utils/codecs';
|
||||
import { type ILogger, Logger } from '../utils/logger';
|
||||
import { patchEncyptionData, writeUint32 } from '../utils/mp4-tools';
|
||||
import { getSampleData, parseInitSegment } from '../utils/mp4-tools';
|
||||
import type { HlsEventEmitter } from '../events';
|
||||
import type { TrackFragmentSample } from './mp4-generator';
|
||||
import type { HlsConfig } from '../config';
|
||||
import type { HlsEventEmitter } from '../events';
|
||||
import type { DecryptData } from '../loader/level-key';
|
||||
import type {
|
||||
DemuxedAudioTrack,
|
||||
@@ -32,6 +32,7 @@ import type { InitData, InitDataTrack, TrackTimes } from '../utils/mp4-tools';
|
||||
import type { TimestampOffset } from '../utils/timescale-conversion';
|
||||
|
||||
class PassThroughRemuxer extends Logger implements Remuxer {
|
||||
private readonly observer: HlsEventEmitter;
|
||||
private emitInitSegment: boolean = false;
|
||||
private audioCodec?: string;
|
||||
private videoCodec?: string;
|
||||
@@ -48,9 +49,16 @@ class PassThroughRemuxer extends Logger implements Remuxer {
|
||||
logger: ILogger,
|
||||
) {
|
||||
super('passthrough-remuxer', logger);
|
||||
this.observer = observer;
|
||||
}
|
||||
|
||||
public destroy() {}
|
||||
public destroy() {
|
||||
if (this.observer) {
|
||||
this.observer.removeAllListeners();
|
||||
}
|
||||
// @ts-ignore
|
||||
this.observer = null;
|
||||
}
|
||||
|
||||
public resetTimeStamp(defaultInitPTS: TimestampOffset | null) {
|
||||
this.lastEndTime = null;
|
||||
@@ -393,14 +401,15 @@ class PassThroughRemuxer extends Logger implements Remuxer {
|
||||
const startDTS = decodeTime - initPTS.baseTime / initPTS.timescale;
|
||||
const endDTS = startDTS + duration;
|
||||
const startPTS =
|
||||
baseOffsetSamples?.ptsMin !== undefined
|
||||
hasVideo && baseOffsetSamples?.ptsMin !== undefined
|
||||
? baseOffsetSamples.ptsMin / baseOffsetSamples.timescale -
|
||||
initPTS.baseTime / initPTS.timescale
|
||||
: startDTS;
|
||||
const endPTS = baseOffsetSamples?.ptsMax
|
||||
? baseOffsetSamples.ptsMax / baseOffsetSamples.timescale -
|
||||
initPTS.baseTime / initPTS.timescale
|
||||
: endDTS;
|
||||
const endPTS =
|
||||
hasVideo && baseOffsetSamples?.ptsMax
|
||||
? baseOffsetSamples.ptsMax / baseOffsetSamples.timescale -
|
||||
initPTS.baseTime / initPTS.timescale
|
||||
: endDTS;
|
||||
|
||||
// For troubleshooting duplicates of https://github.com/video-dev/hls.js/issues/6777
|
||||
// if (videoSampleTimestamps) {
|
||||
|
||||
@@ -32,9 +32,7 @@ export function shouldAlignOnDiscontinuities(
|
||||
|
||||
function adjustFragmentStart(frag: Fragment, sliding: number) {
|
||||
const start = frag.start + sliding;
|
||||
frag.startPTS = start;
|
||||
frag.setStart(start);
|
||||
frag.endPTS = start + frag.duration;
|
||||
}
|
||||
|
||||
export function adjustSlidingStart(sliding: number, details: LevelDetails) {
|
||||
@@ -148,7 +146,9 @@ export function alignMediaPlaylistByPDT(
|
||||
frag = findFirstFragWithCC(fragments, targetCC);
|
||||
}
|
||||
if (!refFrag || !frag) {
|
||||
refFrag = refFragments[Math.floor(refFragments.length / 2)];
|
||||
refFrag =
|
||||
refFragments[Math.floor(refFragments.length / 2)] ||
|
||||
refFragments.filter((f) => !!f)[0];
|
||||
frag =
|
||||
findFirstFragWithCC(fragments, refFrag.cc) ||
|
||||
fragments[Math.floor(fragments.length / 2)];
|
||||
|
||||
@@ -294,6 +294,8 @@ export function mergeDetails(
|
||||
(oldPart: Part, newPart: Part) => {
|
||||
newPart.elementaryStreams = oldPart.elementaryStreams;
|
||||
newPart.stats = oldPart.stats;
|
||||
// Use locally set gap or GAP attribute introduced in playlist
|
||||
newPart.gap = oldPart.gap || newPart.gap;
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -759,11 +759,12 @@ export function getSampleData(
|
||||
type: track.type,
|
||||
});
|
||||
// get start DTS
|
||||
let baseTime: number | undefined;
|
||||
const tfdt = findBox(traf, ['tfdt'])[0];
|
||||
|
||||
if (tfdt as any) {
|
||||
const version = tfdt[0];
|
||||
let baseTime = readUint32(tfdt, 4);
|
||||
baseTime = readUint32(tfdt, 4);
|
||||
if (version === 1) {
|
||||
// If value is too large, assume signed 64-bit. Negative track fragment decode times are invalid, but they exist in the wild.
|
||||
// This prevents large values from being used for initPTS, which can cause playlist sync issues.
|
||||
@@ -815,7 +816,7 @@ export function getSampleData(
|
||||
}
|
||||
|
||||
const truns = findBox(traf, ['trun']);
|
||||
let sampleDTS = trackTimes.start || 0;
|
||||
let sampleDTS = baseTime || 0;
|
||||
let rawDuration = 0;
|
||||
let sampleDuration = defaultSampleDuration;
|
||||
for (let j = 0; j < truns.length; j++) {
|
||||
|
||||
@@ -18,8 +18,6 @@ use(sinonChai);
|
||||
|
||||
const mockReferenceFrag = objToFragment({
|
||||
start: 20,
|
||||
startPTS: 20,
|
||||
endPTS: 24,
|
||||
duration: 4,
|
||||
cc: 0,
|
||||
});
|
||||
@@ -27,22 +25,16 @@ const mockReferenceFrag = objToFragment({
|
||||
const mockFrags = [
|
||||
{
|
||||
start: 0,
|
||||
startPTS: 0,
|
||||
endPTS: 4,
|
||||
duration: 4,
|
||||
cc: 0,
|
||||
},
|
||||
{
|
||||
start: 4,
|
||||
startPTS: 4,
|
||||
endPTS: 8,
|
||||
duration: 4,
|
||||
cc: 1,
|
||||
},
|
||||
{
|
||||
start: 8,
|
||||
startPTS: 8,
|
||||
endPTS: 16,
|
||||
duration: 8,
|
||||
cc: 1,
|
||||
},
|
||||
@@ -58,29 +50,23 @@ describe('discontinuities', function () {
|
||||
const expected = [
|
||||
{
|
||||
start: 20,
|
||||
startPTS: 20,
|
||||
endPTS: 24,
|
||||
duration: 4,
|
||||
cc: 0,
|
||||
},
|
||||
{
|
||||
start: 24,
|
||||
startPTS: 24,
|
||||
endPTS: 28,
|
||||
duration: 4,
|
||||
cc: 1,
|
||||
},
|
||||
{
|
||||
start: 28,
|
||||
startPTS: 28,
|
||||
endPTS: 36,
|
||||
duration: 8,
|
||||
cc: 1,
|
||||
},
|
||||
].map(objToFragment);
|
||||
|
||||
adjustSlidingStart(mockReferenceFrag.start, details);
|
||||
expect(expected).to.deep.equal(details.fragments);
|
||||
expect(details.fragments).to.deep.equal(expected);
|
||||
expect(details.alignedSliding).to.be.true;
|
||||
});
|
||||
|
||||
@@ -94,30 +80,22 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 18,
|
||||
startPTS: undefined,
|
||||
endPTS: undefined,
|
||||
duration: 2,
|
||||
programDateTime: 1629821766107,
|
||||
},
|
||||
{
|
||||
start: 20,
|
||||
startPTS: undefined,
|
||||
endPTS: 22,
|
||||
duration: 2,
|
||||
programDateTime: 1629821768107,
|
||||
},
|
||||
{
|
||||
start: 22,
|
||||
startPTS: 22,
|
||||
endPTS: 30,
|
||||
duration: 8,
|
||||
programDateTime: 1629821770107,
|
||||
},
|
||||
].map(objToFragment),
|
||||
fragmentHint: objToFragment({
|
||||
start: 30,
|
||||
startPTS: 30,
|
||||
endPTS: 32,
|
||||
duration: 2,
|
||||
programDateTime: 1629821778107,
|
||||
}),
|
||||
@@ -128,8 +106,6 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 18,
|
||||
startPTS: undefined,
|
||||
endPTS: undefined,
|
||||
duration: 2,
|
||||
programDateTime: 1629821768107,
|
||||
},
|
||||
@@ -144,30 +120,22 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 16,
|
||||
startPTS: 16,
|
||||
endPTS: 18,
|
||||
duration: 2,
|
||||
programDateTime: 1629821766107,
|
||||
},
|
||||
{
|
||||
start: 18,
|
||||
startPTS: 18,
|
||||
endPTS: 20,
|
||||
duration: 2,
|
||||
programDateTime: 1629821768107,
|
||||
},
|
||||
{
|
||||
start: 20,
|
||||
startPTS: 20,
|
||||
endPTS: 28,
|
||||
duration: 8,
|
||||
programDateTime: 1629821770107,
|
||||
},
|
||||
].map(objToFragment),
|
||||
fragmentHint: objToFragment({
|
||||
start: 28,
|
||||
startPTS: 28,
|
||||
endPTS: 30,
|
||||
duration: 2,
|
||||
programDateTime: 1629821778107,
|
||||
}),
|
||||
@@ -197,32 +165,24 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 20,
|
||||
startPTS: 20,
|
||||
endPTS: 24,
|
||||
duration: 4,
|
||||
cc: 1,
|
||||
programDateTime: 1503892800000,
|
||||
},
|
||||
{
|
||||
start: 24,
|
||||
startPTS: 24,
|
||||
endPTS: 28,
|
||||
duration: 4,
|
||||
cc: 2,
|
||||
programDateTime: 1503892850000,
|
||||
},
|
||||
{
|
||||
start: 28,
|
||||
startPTS: 28,
|
||||
endPTS: 36,
|
||||
duration: 8,
|
||||
cc: 3,
|
||||
programDateTime: 1501111110000,
|
||||
},
|
||||
{
|
||||
start: 28,
|
||||
startPTS: 28,
|
||||
endPTS: 36,
|
||||
duration: 8,
|
||||
cc: 3,
|
||||
programDateTime: 1501111118000,
|
||||
@@ -235,32 +195,24 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 0,
|
||||
startPTS: 0,
|
||||
endPTS: 4,
|
||||
duration: 4,
|
||||
cc: 2,
|
||||
programDateTime: 1503892850000,
|
||||
},
|
||||
{
|
||||
start: 4,
|
||||
startPTS: 4,
|
||||
endPTS: 8,
|
||||
duration: 4,
|
||||
cc: 3,
|
||||
programDateTime: 1501111110000,
|
||||
},
|
||||
{
|
||||
start: 8,
|
||||
startPTS: 8,
|
||||
endPTS: 12,
|
||||
duration: 4,
|
||||
cc: 3,
|
||||
programDateTime: 1501111114000,
|
||||
},
|
||||
{
|
||||
start: 12,
|
||||
startPTS: 12,
|
||||
endPTS: 16,
|
||||
duration: 4,
|
||||
cc: 4,
|
||||
programDateTime: 1503892854000,
|
||||
@@ -276,32 +228,24 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 24,
|
||||
startPTS: 24,
|
||||
endPTS: 28,
|
||||
duration: 4,
|
||||
cc: 2,
|
||||
programDateTime: 1503892850000,
|
||||
},
|
||||
{
|
||||
start: 28,
|
||||
startPTS: 28,
|
||||
endPTS: 32,
|
||||
duration: 4,
|
||||
cc: 3,
|
||||
programDateTime: 1501111110000,
|
||||
},
|
||||
{
|
||||
start: 32,
|
||||
startPTS: 32,
|
||||
endPTS: 36,
|
||||
duration: 4,
|
||||
cc: 3,
|
||||
programDateTime: 1501111114000,
|
||||
},
|
||||
{
|
||||
start: 36,
|
||||
startPTS: 36,
|
||||
endPTS: 40,
|
||||
duration: 4,
|
||||
cc: 4,
|
||||
programDateTime: 1503892854000,
|
||||
@@ -326,24 +270,18 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 20,
|
||||
startPTS: 20,
|
||||
endPTS: 24,
|
||||
duration: 4,
|
||||
cc: 0,
|
||||
programDateTime: 1503892800000,
|
||||
},
|
||||
{
|
||||
start: 24,
|
||||
startPTS: 24,
|
||||
endPTS: 28,
|
||||
duration: 4,
|
||||
cc: 1,
|
||||
programDateTime: 1503892804000,
|
||||
},
|
||||
{
|
||||
start: 28,
|
||||
startPTS: 28,
|
||||
endPTS: 36,
|
||||
duration: 8,
|
||||
cc: 1,
|
||||
programDateTime: 1503892808000,
|
||||
@@ -356,24 +294,18 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 0,
|
||||
startPTS: 0,
|
||||
endPTS: 4,
|
||||
duration: 4,
|
||||
cc: 2,
|
||||
programDateTime: 1503892850000,
|
||||
},
|
||||
{
|
||||
start: 4,
|
||||
startPTS: 4,
|
||||
endPTS: 8,
|
||||
duration: 4,
|
||||
cc: 2,
|
||||
programDateTime: 1503892854000,
|
||||
},
|
||||
{
|
||||
start: 8,
|
||||
startPTS: 8,
|
||||
endPTS: 16,
|
||||
duration: 8,
|
||||
cc: 3,
|
||||
programDateTime: 1503892858000,
|
||||
@@ -389,8 +321,6 @@ describe('discontinuities', function () {
|
||||
fragments: [
|
||||
{
|
||||
start: 70,
|
||||
startPTS: 70,
|
||||
endPTS: 74,
|
||||
duration: 4,
|
||||
cc: 2,
|
||||
programDateTime: 1503892850000,
|
||||
@@ -398,8 +328,6 @@ describe('discontinuities', function () {
|
||||
},
|
||||
{
|
||||
start: 74,
|
||||
startPTS: 74,
|
||||
endPTS: 78,
|
||||
duration: 4,
|
||||
cc: 2,
|
||||
programDateTime: 1503892854000,
|
||||
@@ -407,8 +335,6 @@ describe('discontinuities', function () {
|
||||
},
|
||||
{
|
||||
start: 78,
|
||||
startPTS: 78,
|
||||
endPTS: 86,
|
||||
duration: 8,
|
||||
cc: 3,
|
||||
programDateTime: 1503892858000,
|
||||
@@ -431,10 +357,9 @@ describe('discontinuities', function () {
|
||||
describe('alignDiscontinuities', function () {
|
||||
it('aligns playlists (LevelDetails fragments starts) based on overlapping discontinuity sequence change', function () {
|
||||
const prevDetails = objToLevelDetails({
|
||||
fragments: [
|
||||
mockReferenceFrag,
|
||||
{ start: 24, startPTS: 24, endPTS: 28, duration: 4, cc: 1 },
|
||||
].map(objToFragment),
|
||||
fragments: [mockReferenceFrag, { start: 24, duration: 4, cc: 1 }].map(
|
||||
objToFragment,
|
||||
),
|
||||
});
|
||||
const curDetails = objToLevelDetails({
|
||||
fragments: mockFrags.map(objToFragment),
|
||||
@@ -448,8 +373,8 @@ describe('discontinuities', function () {
|
||||
const prevDetails = objToLevelDetails({
|
||||
fragments: [
|
||||
mockReferenceFrag,
|
||||
{ start: 24, startPTS: 24, endPTS: 28, duration: 4, cc: 1 },
|
||||
{ start: 28, startPTS: 28, endPTS: 32, duration: 4, cc: 2 },
|
||||
{ start: 24, duration: 4, cc: 1 },
|
||||
{ start: 28, duration: 4, cc: 2 },
|
||||
].map(objToFragment),
|
||||
});
|
||||
const curDetails = objToLevelDetails({
|
||||
@@ -464,15 +389,15 @@ describe('discontinuities', function () {
|
||||
const prevDetails = objToLevelDetails({
|
||||
fragments: [
|
||||
mockReferenceFrag,
|
||||
{ start: 24, startPTS: 24, endPTS: 28, duration: 4.5, cc: 1 },
|
||||
{ start: 28.5, startPTS: 28, endPTS: 32, duration: 4, cc: 2 },
|
||||
{ start: 24, duration: 4.5, cc: 1 },
|
||||
{ start: 28.5, duration: 4, cc: 2 },
|
||||
].map(objToFragment),
|
||||
});
|
||||
const curDetails = objToLevelDetails({
|
||||
fragments: [
|
||||
{ start: 0, startPTS: 0, endPTS: 4, duration: 4.5, cc: 1 },
|
||||
{ start: 4.5, startPTS: 4.5, endPTS: 8.5, duration: 4, cc: 2 },
|
||||
{ start: 8.5, startPTS: 4.5, endPTS: 12.5, duration: 4, cc: 3 },
|
||||
{ start: 0, duration: 4.5, cc: 1 },
|
||||
{ start: 4.5, duration: 4, cc: 2 },
|
||||
{ start: 8.5, duration: 4, cc: 3 },
|
||||
].map(objToFragment),
|
||||
});
|
||||
alignDiscontinuities(curDetails, prevDetails, logger);
|
||||
|
||||
Reference in New Issue
Block a user