From dd500285c2bcb605b54f70ed27c3ea8f204c5a6d Mon Sep 17 00:00:00 2001 From: wjywbs Date: Mon, 8 Jan 2024 03:33:31 -0500 Subject: [PATCH] perf: ts parser O(n^2) performance bug. (#6035) This caused high cpu usage when the ts file segments are large. --- lib/util/ts_parser.js | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/util/ts_parser.js b/lib/util/ts_parser.js index a7b1dfff5a..331dcac4d2 100644 --- a/lib/util/ts_parser.js +++ b/lib/util/ts_parser.js @@ -32,7 +32,7 @@ shaka.util.TsParser = class { /** @private {?string} */ this.videoCodec_ = null; - /** @private {!Array.} */ + /** @private {!Array.>} */ this.videoData_ = []; /** @private {!Array.} */ @@ -44,7 +44,7 @@ shaka.util.TsParser = class { /** @private {?string} */ this.audioCodec_ = null; - /** @private {!Array.} */ + /** @private {!Array.>} */ this.audioData_ = []; /** @private {!Array.} */ @@ -53,7 +53,7 @@ shaka.util.TsParser = class { /** @private {?number} */ this.id3Pid_ = null; - /** @private {!Array.} */ + /** @private {!Array.>} */ this.id3Data_ = []; } @@ -79,7 +79,6 @@ shaka.util.TsParser = class { */ parse(data) { const packetLength = shaka.util.TsParser.PacketLength_; - const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; // A TS fragment should contain at least 3 TS packets, a PAT, a PMT, and // one PID. @@ -162,12 +161,11 @@ shaka.util.TsParser = class { case this.videoPid_: { const videoData = data.subarray(offset, start + packetLength); if (payloadUnitStartIndicator) { - this.videoData_.push(videoData); + this.videoData_.push([videoData]); } else if (this.videoData_.length) { const prevVideoData = this.videoData_[this.videoData_.length - 1]; if (prevVideoData) { - this.videoData_[this.videoData_.length - 1] = - Uint8ArrayUtils.concat(prevVideoData, videoData); + this.videoData_[this.videoData_.length - 1].push(videoData); } } break; @@ -175,12 +173,11 @@ shaka.util.TsParser = class { case this.audioPid_: { const audioData = data.subarray(offset, start + packetLength); if (payloadUnitStartIndicator) { - this.audioData_.push(audioData); + this.audioData_.push([audioData]); } else if (this.audioData_.length) { const prevAudioData = this.audioData_[this.audioData_.length - 1]; if (prevAudioData) { - this.audioData_[this.audioData_.length - 1] = - Uint8ArrayUtils.concat(prevAudioData, audioData); + this.audioData_[this.audioData_.length - 1].push(audioData); } } break; @@ -188,12 +185,11 @@ shaka.util.TsParser = class { case this.id3Pid_: { const id3Data = data.subarray(offset, start + packetLength); if (payloadUnitStartIndicator) { - this.id3Data_.push(id3Data); + this.id3Data_.push([id3Data]); } else if (this.id3Data_.length) { const prevId3Data = this.id3Data_[this.id3Data_.length - 1]; if (prevId3Data) { - this.id3Data_[this.id3Data_.length - 1] = - Uint8ArrayUtils.concat(prevId3Data, id3Data); + this.id3Data_[this.id3Data_.length - 1].push(id3Data); } } break; @@ -588,7 +584,8 @@ shaka.util.TsParser = class { getMetadata() { const timescale = shaka.util.TsParser.Timescale; const metadata = []; - for (const id3Data of this.id3Data_) { + for (const id3DataArray of this.id3Data_) { + const id3Data = shaka.util.Uint8ArrayUtils.concat(...id3DataArray); const pes = this.parsePES_(id3Data); if (pes) { metadata.push({ @@ -612,7 +609,8 @@ shaka.util.TsParser = class { getAudioData() { if (this.audioData_.length && !this.audioPes_.length) { let sort = false; - for (const audioData of this.audioData_) { + for (const audioDataArray of this.audioData_) { + const audioData = shaka.util.Uint8ArrayUtils.concat(...audioDataArray); const pes = this.parsePES_(audioData); let previousPes = this.audioPes_.length ? this.audioPes_[this.audioPes_.length - 1] : null; @@ -654,7 +652,8 @@ shaka.util.TsParser = class { getVideoData(naluProcessing = true) { if (this.videoData_.length && !this.videoPes_.length) { let sort = false; - for (const videoData of this.videoData_) { + for (const videoDataArray of this.videoData_) { + const videoData = shaka.util.Uint8ArrayUtils.concat(...videoDataArray); const pes = this.parsePES_(videoData); let previousPes = this.videoPes_.length ? this.videoPes_[this.videoPes_.length - 1] : null;