diff --git a/fixtures/hls/index.js b/fixtures/hls/index.js index ba275127..dca5b91d 100644 --- a/fixtures/hls/index.js +++ b/fixtures/hls/index.js @@ -14,7 +14,8 @@ function defaultOpt() { preloadTime: 180, bufferBehind: 10, maxJumpDistance: 3, - startTime: 0 + startTime: 0, + forceFixLargeGap:false, } } var cachedOpt = localStorage.getItem('xg:test:hls:opt') diff --git a/packages/xgplayer-hls/src/hls/buffer-service/index.js b/packages/xgplayer-hls/src/hls/buffer-service/index.js index 652f0f51..f7ccdb12 100644 --- a/packages/xgplayer-hls/src/hls/buffer-service/index.js +++ b/packages/xgplayer-hls/src/hls/buffer-service/index.js @@ -78,10 +78,10 @@ export class BufferService { const chunk = videoChunk || audioChunk if (!chunk) return if (TsDemuxer.probe(chunk)) { - if (!this._transmuxer) this._transmuxer = new Transmuxer(this.hls, false, !this._softVideo) + if (!this._transmuxer) this._transmuxer = new Transmuxer(this.hls, false, !this._softVideo, this.hls.config.forceFixLargeGap) } else if (MP4Parser.probe(chunk)) { if (this._softVideo) { - if (!this._transmuxer) this._transmuxer = new Transmuxer(this.hls, true) + if (!this._transmuxer) this._transmuxer = new Transmuxer(this.hls, true, null, this.hls.config.forceFixLargeGap) } else { this._directAppend = true let mix = false diff --git a/packages/xgplayer-hls/src/hls/buffer-service/transmuxer/index.js b/packages/xgplayer-hls/src/hls/buffer-service/transmuxer/index.js index 6cc35a8d..b640529b 100644 --- a/packages/xgplayer-hls/src/hls/buffer-service/transmuxer/index.js +++ b/packages/xgplayer-hls/src/hls/buffer-service/transmuxer/index.js @@ -7,8 +7,9 @@ const logger = new Logger('Transmuxer') export class Transmuxer { _initSegmentId = '' - constructor (hls, isMP4, needRemux) { + constructor (hls, isMP4, needRemux, forceFixLargeGap) { this.hls = hls + this.forceFixLargeGap = forceFixLargeGap this._demuxer = isMP4 ? new FMP4Demuxer() : new TsDemuxer() this._isMP4 = isMP4 if (needRemux) this._remuxer = new FMP4Remuxer(this._demuxer.videoTrack, this._demuxer.audioTrack) @@ -20,7 +21,7 @@ export class Transmuxer { if (this._isMP4) { demuxer.demux(videoChunk, audioChunk) } else { - demuxer.demuxAndFix(concatUint8Array(videoChunk, audioChunk), discontinuity, contiguous, startTime) + demuxer.demuxAndFix(concatUint8Array(videoChunk, audioChunk), discontinuity, contiguous, startTime, this.forceFixLargeGap) } } catch (error) { throw new StreamingError(ERR.DEMUX, ERR.SUB_TYPES.HLS, error) diff --git a/packages/xgplayer-hls/src/hls/config.js b/packages/xgplayer-hls/src/hls/config.js index 9b891735..fb22aa85 100644 --- a/packages/xgplayer-hls/src/hls/config.js +++ b/packages/xgplayer-hls/src/hls/config.js @@ -26,6 +26,7 @@ * preferMMS?: boolean * preferMMSStreaming?: boolean, * mseLowLatency?: boolean, + * forceFixLargeGap?:boolean, * }} HlsOption */ @@ -57,6 +58,7 @@ export function getConfig (cfg) { preferMMS: false, preferMMSStreaming: false, mseLowLatency: true, // mse 低延迟模式渲染 https://issues.chromium.org/issues/41161663 + forceFixLargeGap:false, // 强制修复音视频PTS LargeGap, PTS从0开始 ...cfg, media } diff --git a/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js b/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js index 03454aaf..70901d8a 100644 --- a/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js +++ b/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js @@ -16,6 +16,8 @@ export class TsFixer { this.metadataTrack = metadataTrack this._baseDts = -1 + this._baseVideoDts = -1 + this._baseAudioDts = -1 this._baseDtsInited = false this._audioNextPts = undefined @@ -27,9 +29,11 @@ export class TsFixer { this._lastAudioExceptionGapDot = 0 this._lastAudioExceptionOverlapDot = 0 this._lastAudioExceptionLargeGapDot = 0 + + this._needForceFixLargeGap = false } - fix (startTime = 0, discontinuity = false, contiguous = true) { + fix (startTime = 0, discontinuity = false, contiguous = true, forceFixLargeGap = false) { startTime = Math.round(startTime * 90000) const videoTrack = this.videoTrack const audioTrack = this.audioTrack @@ -41,7 +45,7 @@ export class TsFixer { const firstVideoSample = vSamples[0] const firstAudioSample = aSamples[0] - + this._needForceFixLargeGap = forceFixLargeGap // consider av delta let vaDelta = 0 @@ -57,6 +61,8 @@ export class TsFixer { if (discontinuity) { this._calculateBaseDts(this.audioTrack, this.videoTrack) this._baseDts -= startTime + this._baseAudioDts -= startTime + this._baseVideoDts -= startTime } // id discontinue, recalc nextDts, consider av delta of firstframe @@ -72,6 +78,10 @@ export class TsFixer { this._videoNextDts = vaDelta > 0 ? startTime + vaDelta : startTime this._audioNextPts = vaDelta > 0 ? startTime : startTime - vaDelta + if (this._needForceFixLargeGap){ + this._videoNextDts = 0 + this._audioNextPts = 0 + } const vDeltaToNextDts = firstVideoSample ? firstVideoSample.dts - this._baseDts - this._videoNextDts : 0 const aDeltaToNextDts = firstAudioSample ? firstAudioSample.pts - this._baseDts - this._audioNextPts : 0 @@ -109,8 +119,8 @@ export class TsFixer { if (!samples.length) return samples.forEach(x => { - x.dts -= this._baseDts - x.pts -= this._baseDts + x.dts -= this._needForceFixLargeGap ? this._baseVideoDts : this._baseDts + x.pts -= this._needForceFixLargeGap ? this._baseVideoDts : this._baseDts }) if (this._videoNextDts === undefined) { @@ -220,7 +230,7 @@ export class TsFixer { if (!samples.length) return samples.forEach(x => { - x.pts -= this._baseDts + x.pts -= this._needForceFixLargeGap ? this._baseAudioDts : this._baseDts x.dts = x.pts }) @@ -240,16 +250,18 @@ export class TsFixer { if (audioSamps.length) { audioTrack.baseDts = audioBasePts = audioSamps[0].pts + this._baseAudioDts = audioBasePts } if (videoSamps.length) { videoTrack.baseDts = videoBaseDts = videoSamps[0].dts + this._baseVideoDts = videoBaseDts } this._baseDts = Math.min(audioBasePts, videoBaseDts) const delta = videoBaseDts - audioBasePts - + let largeGap = false if (Number.isFinite(delta) && Math.abs(delta) > LARGE_AV_FIRST_FRAME_GAP) { videoTrack.warnings.push({ type: WarningType.LARGE_AV_SHIFT, @@ -258,8 +270,15 @@ export class TsFixer { baseDts: this._baseDts, delta }) + largeGap = true + } + if (!this._baseDtsInited){ + if (largeGap && this._needForceFixLargeGap) { + this._needForceFixLargeGap = true + } else { + this._needForceFixLargeGap = false + } } - this._baseDtsInited = true return true } diff --git a/packages/xgplayer-transmuxer/src/mpeg-ts/index.js b/packages/xgplayer-transmuxer/src/mpeg-ts/index.js index 6f9cf1cc..022eae68 100644 --- a/packages/xgplayer-transmuxer/src/mpeg-ts/index.js +++ b/packages/xgplayer-transmuxer/src/mpeg-ts/index.js @@ -155,8 +155,8 @@ export class TsDemuxer { * @param {boolean} [discontinuity=false] * @param {boolean} [contiguous=true] */ - fix (startTime, discontinuity, contiguous) { - this._fixer.fix(startTime, discontinuity, contiguous) + fix (startTime, discontinuity, contiguous, forceFixLargeGap) { + this._fixer.fix(startTime, discontinuity, contiguous, forceFixLargeGap) return { videoTrack: this.videoTrack, audioTrack: this.audioTrack, @@ -170,9 +170,9 @@ export class TsDemuxer { * @param {boolean} [contiguous=true] * @param {number} [startTime=0] */ - demuxAndFix (data, discontinuity, contiguous, startTime) { + demuxAndFix (data, discontinuity, contiguous, startTime, forceFixLargeGap) { this.demux(data, discontinuity, contiguous) - return this.fix(startTime, discontinuity, contiguous) + return this.fix(startTime, discontinuity, contiguous, forceFixLargeGap) } /**