Skip to content

Commit 50e4f35

Browse files
authored
General release Aug 20 2025 (#24)
Changes: - Updated LCEVCdecJS to expect newly formatted dual-track streams. Fixes: - Resolved a possible use-after-free bug in LCEVCdecJS. - Fixed unreliable isLive checks for dual-track contents. - Ensure onExitPictureInPicture listeners are properly removed when LCEVCdecJS instance is destroyed.
1 parent deb815c commit 50e4f35

File tree

5 files changed

+40
-6
lines changed

5 files changed

+40
-6
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "lcevc_dec.js",
3-
"version": "1.2.1",
3+
"version": "1.3.0",
44
"description": "V-Nova MPEG-5 LCEVC Decoder",
55
"main": "dist/lcevc_dec.min.js",
66
"scripts": {
@@ -51,6 +51,7 @@
5151
"@rollup/plugin-replace": "^4.0.0",
5252
"@rollup/plugin-typescript": "^8.5.0",
5353
"@types/estree": "^1.0.0",
54+
"@types/node": "^22.17.1",
5455
"@typescript-eslint/eslint-plugin": "^5.0.0",
5556
"@typescript-eslint/parser": "^5.0.0",
5657
"babel-loader": "^8.2.2",

src/controllers/video_controller.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ class VideoControls {
175175

176176
/** @private @type {boolean} */
177177
#isLive = null;
178+
179+
/** @private @type {boolean} */
180+
#hasCheckedLive = false;
178181
// #endregion
179182

180183
// #region Events
@@ -834,15 +837,23 @@ class VideoControls {
834837
*
835838
* If the given time is greater than 1, then the video is a live one.
836839
* This can be a false positive if a live stream current time is less than 1
837-
* when this is call.
840+
* when this is called.
841+
*
842+
* This method can only be called once. Subsequent calls have no effect.
838843
*
839844
* @param {!number} currentTime The current time of the video.
840845
* @returns {Result} The status code.
841846
* @memberof VideoControls
842847
* @public
843848
*/
844849
_checkIsLive(currentTime) {
850+
if (this.#hasCheckedLive) {
851+
return Result.OK;
852+
}
853+
845854
this.#isLive = currentTime > 1;
855+
this.#hasCheckedLive = true;
856+
846857
return Result.OK;
847858
}
848859

src/demux/demuxer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ class Demuxer {
386386
// Raw LCEVC data can be directly passed to the residual store, whereas encapsulated
387387
// LCEVC data will need further demuxing and processing
388388
if (this.#isRawLcevc) {
389+
Demuxer.convertLengthPrefixToAnnexB(data);
389390
this._demuxedLcevcData(data, ...frameSample.slice(0, -1), level);
390391
} else {
391392
Demuxer.convertLengthPrefixToAnnexB(data);

src/dpi.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ class DPI {
789789
* @public
790790
*/
791791
_reset(residualStore, timestamp, profileSwitch) {
792-
Log.msg('reset');
792+
Log.msg('Reset');
793793
this.#decoderResetProgress = true;
794794
libDPI._perseus_decoder_close(this.#lcevcDecoderPointer);
795795
this.#lcevcDecoderPointer = libDPI._perseus_decoder_open_wrapper(1);
@@ -807,9 +807,11 @@ class DPI {
807807
}
808808

809809
if (!parsedLcevc) {
810-
Log.warn(`Failed to load and parse lcevc data for timestamp: ${timestamp}`);
810+
Log.warn(`Failed to load and parse LCEVC data for timestamp: ${timestamp}`);
811811
if (libDPI && this.#pssData.pointer) {
812+
Log.debug('Freeing and re-allocating LCEVC data.');
812813
this.#freePssData();
814+
this.#initPssData();
813815
}
814816
this.#decoderResetProgress = false;
815817
return Result.FAIL;
@@ -826,6 +828,18 @@ class DPI {
826828
return Result.OK;
827829
}
828830

831+
/**
832+
* Init the buffer for LCEVC data with an initial size of 1.
833+
*
834+
* @returns {Result} The status code.
835+
* @memberof DPI
836+
* @private
837+
*/
838+
#initPssData() {
839+
this.#pssData = { pointer: _createDataPointer(libDPI, new Uint8Array(1)), size: 1 };
840+
return Result.OK;
841+
}
842+
829843
/**
830844
* Clear the allocated data of the LCEVC from the libDPI.
831845
*

src/lcevc_dec.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,9 @@ class LCEVCdec {
18771877
// Clear previous render times because this will cause incorrect
18781878
// audio delay to be calculated, since in PiP mode the
18791879
// render times are inaccurate
1880-
this.#queue._clearPreviousRenderTimes();
1880+
if (this.#queue) {
1881+
this.#queue._clearPreviousRenderTimes();
1882+
}
18811883

18821884
this.#pictureInPicture = {
18831885
active: false,
@@ -2461,6 +2463,11 @@ class LCEVCdec {
24612463
this.#lcevcWorker = null;
24622464
}
24632465

2466+
// Cleanup PictureInPicture listeners.
2467+
if (window.documentPictureInPicture) {
2468+
this.#removeAllListeners(window.documentPictureInPicture, 'enter');
2469+
}
2470+
24642471
// Video listeners.
24652472
this.#unbindVideoEvents();
24662473
this.#eventHandler = null;
@@ -2518,7 +2525,7 @@ class LCEVCdec {
25182525
});
25192526
}
25202527

2521-
console.info('::::: closing LCEVCdec :::::'); // eslint-disable-line
2528+
Log.always('Closing the LCEVC decoder.');
25222529
return Result.OK;
25232530
}
25242531

0 commit comments

Comments
 (0)