diff --git a/fixtures/hls/index.js b/fixtures/hls/index.js index dca5b91d..e32c1814 100644 --- a/fixtures/hls/index.js +++ b/fixtures/hls/index.js @@ -15,7 +15,10 @@ function defaultOpt() { bufferBehind: 10, maxJumpDistance: 3, startTime: 0, - forceFixLargeGap:false, + fixerConfig:{ + forceFixLargeGap:true, + largeGapThreshold: 5 + } } } 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 f7ccdb12..1d59708e 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, this.hls.config.forceFixLargeGap) + if (!this._transmuxer) this._transmuxer = new Transmuxer(this.hls, false, !this._softVideo, this.hls.config.fixerConfig) } else if (MP4Parser.probe(chunk)) { if (this._softVideo) { - if (!this._transmuxer) this._transmuxer = new Transmuxer(this.hls, true, null, this.hls.config.forceFixLargeGap) + if (!this._transmuxer) this._transmuxer = new Transmuxer(this.hls, true, null, this.hls.config.fixerConfig) } 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 b640529b..d8963a4a 100644 --- a/packages/xgplayer-hls/src/hls/buffer-service/transmuxer/index.js +++ b/packages/xgplayer-hls/src/hls/buffer-service/transmuxer/index.js @@ -7,10 +7,9 @@ const logger = new Logger('Transmuxer') export class Transmuxer { _initSegmentId = '' - constructor (hls, isMP4, needRemux, forceFixLargeGap) { + constructor (hls, isMP4, needRemux, fixerConfig) { this.hls = hls - this.forceFixLargeGap = forceFixLargeGap - this._demuxer = isMP4 ? new FMP4Demuxer() : new TsDemuxer() + this._demuxer = isMP4 ? new FMP4Demuxer() : new TsDemuxer(null, null, null, fixerConfig) this._isMP4 = isMP4 if (needRemux) this._remuxer = new FMP4Remuxer(this._demuxer.videoTrack, this._demuxer.audioTrack) } @@ -21,7 +20,7 @@ export class Transmuxer { if (this._isMP4) { demuxer.demux(videoChunk, audioChunk) } else { - demuxer.demuxAndFix(concatUint8Array(videoChunk, audioChunk), discontinuity, contiguous, startTime, this.forceFixLargeGap) + demuxer.demuxAndFix(concatUint8Array(videoChunk, audioChunk), discontinuity, contiguous, startTime) } } 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 fb22aa85..4078baf2 100644 --- a/packages/xgplayer-hls/src/hls/config.js +++ b/packages/xgplayer-hls/src/hls/config.js @@ -58,7 +58,10 @@ export function getConfig (cfg) { preferMMS: false, preferMMSStreaming: false, mseLowLatency: true, // mse 低延迟模式渲染 https://issues.chromium.org/issues/41161663 - forceFixLargeGap:false, // 强制修复音视频PTS LargeGap, PTS从0开始 + fixerConfig: { + forceFixLargeGap:false, // 强制修复音视频PTS LargeGap, PTS从0开始 + largeGapThreshold: 5 // 单位s + }, ...cfg, media } diff --git a/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js b/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js index 70901d8a..3f66d18a 100644 --- a/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js +++ b/packages/xgplayer-transmuxer/src/mpeg-ts/fixer.js @@ -8,9 +8,10 @@ const MAX_SILENT_FRAME_DURATION = 90000 // 1s const AUDIO_EXCETION_LOG_EMIT_DURATION = 5 * 90000 // 5s const MAX_VIDEO_FRAME_DURATION = 90000 // 1s const MAX_DTS_DELTA_WITH_NEXT_CHUNK = 90000 / 2 // 500ms +const LARGE_AV_FIRST_FRAME_FORCE_FIX_THRESHOLD = 90000 * 5 // 5s export class TsFixer { - constructor (videoTrack, audioTrack, metadataTrack) { + constructor (videoTrack, audioTrack, metadataTrack, fixerConfig) { this.videoTrack = videoTrack this.audioTrack = audioTrack this.metadataTrack = metadataTrack @@ -30,10 +31,11 @@ export class TsFixer { this._lastAudioExceptionOverlapDot = 0 this._lastAudioExceptionLargeGapDot = 0 - this._needForceFixLargeGap = false + this._needForceFixLargeGap = fixerConfig?.forceFixLargeGap + this._largeGapThreshold = fixerConfig?.largeGapThreshold || LARGE_AV_FIRST_FRAME_FORCE_FIX_THRESHOLD } - fix (startTime = 0, discontinuity = false, contiguous = true, forceFixLargeGap = false) { + fix (startTime = 0, discontinuity = false, contiguous = true) { startTime = Math.round(startTime * 90000) const videoTrack = this.videoTrack const audioTrack = this.audioTrack @@ -45,7 +47,6 @@ export class TsFixer { const firstVideoSample = vSamples[0] const firstAudioSample = aSamples[0] - this._needForceFixLargeGap = forceFixLargeGap // consider av delta let vaDelta = 0 @@ -270,6 +271,8 @@ export class TsFixer { baseDts: this._baseDts, delta }) + } + if (Number.isFinite(delta) && Math.abs(delta) > this._largeGapThreshold * MAX_SILENT_FRAME_DURATION) { largeGap = true } if (!this._baseDtsInited){ diff --git a/packages/xgplayer-transmuxer/src/mpeg-ts/index.js b/packages/xgplayer-transmuxer/src/mpeg-ts/index.js index 022eae68..2b02d9c0 100644 --- a/packages/xgplayer-transmuxer/src/mpeg-ts/index.js +++ b/packages/xgplayer-transmuxer/src/mpeg-ts/index.js @@ -17,11 +17,11 @@ export class TsDemuxer { * @param {AudioTrack} [audioTrack] * @param {MetadataTrack} [metadataTrack] */ - constructor (videoTrack, audioTrack, metadataTrack) { + constructor (videoTrack, audioTrack, metadataTrack, fixerConfig = {}) { this.videoTrack = videoTrack || new VideoTrack() this.audioTrack = audioTrack || new AudioTrack() this.metadataTrack = metadataTrack || new MetadataTrack() - this._fixer = new TsFixer(this.videoTrack, this.audioTrack, this.metadataTrack) + this._fixer = new TsFixer(this.videoTrack, this.audioTrack, this.metadataTrack, fixerConfig) } /** @@ -155,8 +155,8 @@ export class TsDemuxer { * @param {boolean} [discontinuity=false] * @param {boolean} [contiguous=true] */ - fix (startTime, discontinuity, contiguous, forceFixLargeGap) { - this._fixer.fix(startTime, discontinuity, contiguous, forceFixLargeGap) + fix (startTime, discontinuity, contiguous) { + this._fixer.fix(startTime, discontinuity, contiguous) 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, forceFixLargeGap) { + demuxAndFix (data, discontinuity, contiguous, startTime) { this.demux(data, discontinuity, contiguous) - return this.fix(startTime, discontinuity, contiguous, forceFixLargeGap) + return this.fix(startTime, discontinuity, contiguous) } /**