diff --git a/AUTHORS b/AUTHORS index 80d0dcf9a5..35f7de5ddf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,6 +32,7 @@ Edgeware AB <*@edgeware.tv> Enson Choy Esteban Dosztal Fadomire +Gerardo Meola Gil Gonen Giorgio Gamberoni Giuseppe Samela diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3fea56e8ee..bb1ef9479d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -50,6 +50,7 @@ Enson Choy Esteban Dosztal Fadomire François Beaufort +Gerardo Meola Gil Gonen Giorgio Gamberoni Giuseppe Samela diff --git a/externs/mux.js b/externs/mux.js index 49eecd8f81..efdb20207a 100644 --- a/externs/mux.js +++ b/externs/mux.js @@ -74,6 +74,9 @@ muxjs.mp4.Transmuxer = class { /** Remove all handlers and clean up. */ dispose() {} + + /** Reset captions. */ + resetCaptions() {} }; diff --git a/lib/media/media_source_engine.js b/lib/media/media_source_engine.js index 8844713d01..f4cb07f84f 100644 --- a/lib/media/media_source_engine.js +++ b/lib/media/media_source_engine.js @@ -605,6 +605,12 @@ shaka.media.MediaSourceEngine = class { } if (this.transmuxers_[contentType]) { + // When seeked we should reset the transmuxer captionstreams + // so it does not ignores the captions from previous segments + if (seeked) { + this.transmuxers_[contentType].resetCaptions(); + } + const transmuxedData = await this.transmuxers_[contentType].transmux(data); // For HLS CEA-608/708 CLOSED-CAPTIONS, text data is embedded in diff --git a/lib/media/transmuxer.js b/lib/media/transmuxer.js index df1703c1af..eca30e3c8f 100644 --- a/lib/media/transmuxer.js +++ b/lib/media/transmuxer.js @@ -239,6 +239,12 @@ shaka.media.Transmuxer = class { return this.transmuxPromise_; } + /** + * Reset captions from Transport stream to MP4, using the mux.js library. + */ + resetCaptions() { + this.muxTransmuxer_.resetCaptions(); + } /** * Handles the 'data' event of the transmuxer. diff --git a/test/media/media_source_engine_integration.js b/test/media/media_source_engine_integration.js index c4373b77ca..193aeae2ae 100644 --- a/test/media/media_source_engine_integration.js +++ b/test/media/media_source_engine_integration.js @@ -78,6 +78,18 @@ describe('MediaSourceEngine', () => { type, segment, reference, /* hasClosedCaptions= */ false); } + function appendWithSeek(type, segmentNumber) { + const segment = generators[type] + .getSegment(segmentNumber, Date.now() / 1000); + const reference = dummyReference(type, segmentNumber); + return mediaSourceEngine.appendBuffer( + type, + segment, + reference, + /* hasClosedCaptions= */ false, + /* seeked= */ true); + } + function appendInitWithClosedCaptions(type) { const segment = generators[type].getInitSegment(Date.now() / 1000); const reference = null; @@ -388,6 +400,25 @@ describe('MediaSourceEngine', () => { expect(textDisplayer.appendSpy).toHaveBeenCalledTimes(3); }); + it('extracts CEA-708 captions from previous segment from hls', async () => { + // Load TS file with CEA-708 captions. + metadata = shaka.test.TestScheme.DATA['cea-708_ts']; + generators = shaka.test.TestScheme.GENERATORS['cea-708_ts']; + + const initObject = new Map(); + initObject.set(ContentType.VIDEO, getFakeStream(metadata.video)); + initObject.set(ContentType.TEXT, getFakeStream(metadata.text)); + // Call with forceTransmux = true, so that it will transmux even on + // platforms with native TS support. + await mediaSourceEngine.init(initObject, /* forceTransmux= */ true); + mediaSourceEngine.setSelectedClosedCaptionId('CC1'); + + await append(ContentType.VIDEO, 2); + await appendWithSeek(ContentType.VIDEO, 0); + + expect(textDisplayer.appendSpy).toHaveBeenCalledTimes(6); + }); + it('buffers partial TS video segments in sequence mode', async () => { metadata = shaka.test.TestScheme.DATA['cea-708_ts']; generators = shaka.test.TestScheme.GENERATORS['cea-708_ts'];