From 48adbbf02133fa065360a2fbbe0246e6cade81f2 Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Tue, 24 Apr 2018 16:49:00 +0200 Subject: [PATCH 1/8] rename updateMediaInfo by selectMediaInfo --- src/streaming/Stream.js | 12 +++++------- src/streaming/StreamProcessor.js | 14 +++++++++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/streaming/Stream.js b/src/streaming/Stream.js index da82c4a257..d7531a3b52 100644 --- a/src/streaming/Stream.js +++ b/src/streaming/Stream.js @@ -306,7 +306,7 @@ function Stream(config) { trackChangedEvent = e; manifestUpdater.refreshManifest(); } else { - processor.updateMediaInfo(mediaInfo); + processor.selectMediaInfo(mediaInfo); if (mediaInfo.type !== Constants.FRAGMENTED_TEXT) { abrController.updateTopQualityIndex(mediaInfo); processor.switchTrackAsked(); @@ -358,13 +358,11 @@ function Stream(config) { if (allMediaForType[i].index === mediaInfo.index) { idx = i; } - streamProcessor.updateMediaInfo(allMediaForType[i]); //creates text tracks for all adaptations in one stream processor - } - if (mediaInfo.type === Constants.FRAGMENTED_TEXT) { - streamProcessor.updateMediaInfo(allMediaForType[idx]); //sets the initial media info + streamProcessor.addMediaInfo(allMediaForType[i]); //creates text tracks for all adaptations in one stream processor } + streamProcessor.selectMediaInfo(allMediaForType[idx]); //sets the initial media info } else { - streamProcessor.updateMediaInfo(mediaInfo); + streamProcessor.addMediaInfo(mediaInfo, true); } } @@ -624,7 +622,7 @@ function Stream(config) { let streamProcessor = streamProcessors[i]; let mediaInfo = adapter.getMediaInfoForType(streamInfo, streamProcessor.getType()); abrController.updateTopQualityIndex(mediaInfo); - streamProcessor.updateMediaInfo(mediaInfo); + streamProcessor.addMediaInfo(mediaInfo, true); } if (trackChangedEvent) { diff --git a/src/streaming/StreamProcessor.js b/src/streaming/StreamProcessor.js index 66dbce05bd..d273ce8cd3 100644 --- a/src/streaming/StreamProcessor.js +++ b/src/streaming/StreamProcessor.js @@ -243,14 +243,21 @@ function StreamProcessor(config) { return stream ? stream.getEventController() : null; } - function updateMediaInfo(newMediaInfo) { + function selectMediaInfo(newMediaInfo) { if (newMediaInfo !== mediaInfo && (!newMediaInfo || !mediaInfo || (newMediaInfo.type === mediaInfo.type))) { mediaInfo = newMediaInfo; } + adapter.updateData(this); + } + + function addMediaInfo(newMediaInfo, selectNewMediaInfo) { if (mediaInfoArr.indexOf(newMediaInfo) === -1) { mediaInfoArr.push(newMediaInfo); } - adapter.updateData(this); + + if (selectNewMediaInfo) { + this.selectMediaInfo(newMediaInfo); + } } function getMediaInfoArr() { @@ -368,7 +375,8 @@ function StreamProcessor(config) { isBufferingCompleted: isBufferingCompleted, createBuffer: createBuffer, getStreamInfo: getStreamInfo, - updateMediaInfo: updateMediaInfo, + selectMediaInfo: selectMediaInfo, + addMediaInfo: addMediaInfo, switchTrackAsked: switchTrackAsked, getMediaInfoArr: getMediaInfoArr, getMediaInfo: getMediaInfo, From 4917fe02fc8d69d3b57a167928c16adf85f07a69 Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Tue, 24 Apr 2018 16:52:48 +0200 Subject: [PATCH 2/8] element in streamProcessors array is a streamProcessor --- src/streaming/Stream.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/streaming/Stream.js b/src/streaming/Stream.js index d7531a3b52..adb803243b 100644 --- a/src/streaming/Stream.js +++ b/src/streaming/Stream.js @@ -513,13 +513,13 @@ function Stream(config) { function getMediaInfo(type) { const ln = streamProcessors.length; - let mediaCtrl = null; + let streamProcessor = null; for (let i = 0; i < ln; i++) { - mediaCtrl = streamProcessors[i]; + streamProcessor = streamProcessors[i]; - if (mediaCtrl.getType() === type) { - return mediaCtrl.getMediaInfo(); + if (streamProcessor.getType() === type) { + return streamProcessor.getMediaInfo(); } } From a5d2d892b1b392975600d69b8b1da35091e02fba Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Tue, 24 Apr 2018 17:24:01 +0200 Subject: [PATCH 3/8] in notFragmentedTextBuffer case, call the init request (request to load subtitles data) only if this request has not been already downloaded. --- .../text/NotFragmentedTextBufferController.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/streaming/text/NotFragmentedTextBufferController.js b/src/streaming/text/NotFragmentedTextBufferController.js index 08b3fa62cd..98fafbf554 100644 --- a/src/streaming/text/NotFragmentedTextBufferController.js +++ b/src/streaming/text/NotFragmentedTextBufferController.js @@ -158,26 +158,36 @@ function NotFragmentedTextBufferController(config) { return; } - eventBus.trigger(Events.TIMED_TEXT_REQUESTED, { - index: 0, - sender: e.sender - }); //TODO make index dynamic if referring to MP? + const chunk = initCache.extract(streamProcessor.getStreamInfo().id, e.sender.getCurrentRepresentation().id); + + if (!chunk) { + eventBus.trigger(Events.TIMED_TEXT_REQUESTED, { + index: 0, + sender: e.sender + }); //TODO make index dynamic if referring to MP? + } } function onInitFragmentLoaded(e) { if (e.fragmentModel !== streamProcessor.getFragmentModel() || (!e.chunk.bytes)) { return; } + initCache.save(e.chunk); buffer.append(e.chunk); + + eventBus.trigger(Events.STREAM_COMPLETED, { + request: e.request, + fragmentModel: e.fragmentModel + }); } function switchInitData(streamId, representationId) { const chunk = initCache.extract(streamId, representationId); - if (chunk) { - buffer.append(chunk); - } else { - eventBus.trigger(Events.INIT_REQUESTED, { + + if (!chunk) { + eventBus.trigger(Events.TIMED_TEXT_REQUESTED, { + index: 0, sender: instance }); } From f8036d0862b9d08e6aa2d97df2c7f49ef1e7bf8d Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Wed, 25 Apr 2018 10:41:44 +0200 Subject: [PATCH 4/8] update NotFragmentedTextBufferController use case --- src/streaming/StreamProcessor.js | 2 ++ .../controllers/ScheduleController.js | 2 +- .../text/NotFragmentedTextBufferController.js | 3 ++- src/streaming/text/TextBufferController.js | 1 + src/streaming/text/TextController.js | 20 +++++++++++++++++++ src/streaming/text/TextSourceBuffer.js | 9 ++++++--- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/streaming/StreamProcessor.js b/src/streaming/StreamProcessor.js index d273ce8cd3..e18a07108d 100644 --- a/src/streaming/StreamProcessor.js +++ b/src/streaming/StreamProcessor.js @@ -104,6 +104,7 @@ function StreamProcessor(config) { bufferController = createBufferControllerForType(type); scheduleController = ScheduleController(context).create({ type: type, + mimeType: mimeType, metricsModel: metricsModel, adapter: adapter, dashMetrics: dashMetrics, @@ -339,6 +340,7 @@ function StreamProcessor(config) { } else { controller = TextBufferController(context).create({ type: type, + mimeType: mimeType, metricsModel: metricsModel, mediaPlayerModel: mediaPlayerModel, manifestModel: manifestModel, diff --git a/src/streaming/controllers/ScheduleController.js b/src/streaming/controllers/ScheduleController.js index 7ee6229c0f..6cd6e93c31 100644 --- a/src/streaming/controllers/ScheduleController.js +++ b/src/streaming/controllers/ScheduleController.js @@ -106,7 +106,7 @@ function ScheduleController(config) { textController: textController }); - if (dashManifestModel.getIsTextTrack(type)) { + if (dashManifestModel.getIsTextTrack(config.mimeType)) { eventBus.on(Events.TIMED_TEXT_REQUESTED, onTimedTextRequested, this); } diff --git a/src/streaming/text/NotFragmentedTextBufferController.js b/src/streaming/text/NotFragmentedTextBufferController.js index 98fafbf554..e8717e8a57 100644 --- a/src/streaming/text/NotFragmentedTextBufferController.js +++ b/src/streaming/text/NotFragmentedTextBufferController.js @@ -46,6 +46,7 @@ function NotFragmentedTextBufferController(config) { let errHandler = config.errHandler; let type = config.type; + let mimeType = config.mimeType; let streamProcessor = config.streamProcessor; let instance, @@ -86,7 +87,7 @@ function NotFragmentedTextBufferController(config) { if (!initialized) { const textBuffer = buffer.getBuffer(); if (textBuffer.hasOwnProperty(Constants.INITIALIZE)) { - textBuffer.initialize(type, streamProcessor); + textBuffer.initialize(mimeType, streamProcessor); } initialized = true; } diff --git a/src/streaming/text/TextBufferController.js b/src/streaming/text/TextBufferController.js index 71efd8ca09..7d1b32f08b 100644 --- a/src/streaming/text/TextBufferController.js +++ b/src/streaming/text/TextBufferController.js @@ -67,6 +67,7 @@ function TextBufferController(config) { // in this case, internal buffer controller is a not fragmented text controller object _BufferControllerImpl = NotFragmentedTextBufferController(context).create({ type: config.type, + mimeType: config.mimeType, errHandler: config.errHandler, streamProcessor: config.streamProcessor }); diff --git a/src/streaming/text/TextController.js b/src/streaming/text/TextController.js index 91a0633a60..c86c948206 100644 --- a/src/streaming/text/TextController.js +++ b/src/streaming/text/TextController.js @@ -225,6 +225,8 @@ function TextController() { let config = textSourceBuffer.getConfig(); let fragmentModel = config.fragmentModel; let fragmentedTracks = config.fragmentedTracks; + let mediaInfosArr, + streamProcessor; let oldTrackIdx = textTracks.getCurrentTrackIdx(); if (oldTrackIdx !== idx) { @@ -250,6 +252,24 @@ function TextController() { } } } + } else if (currentTrackInfo && !currentTrackInfo.isFragmented) { + const streamProcessors = streamController.getActiveStreamProcessors(); + for (let i = 0; i < streamProcessors.length; i++) { + if (streamProcessors[i].getType() === Constants.TEXT) { + streamProcessor = streamProcessors[i]; + mediaInfosArr = streamProcessor.getMediaInfoArr(); + break; + } + } + + if (streamProcessor && mediaInfosArr) { + for (let i = 0; i < mediaInfosArr.length; i++) { + if (mediaInfosArr[i].lang === currentTrackInfo.lang) { + streamProcessor.selectMediaInfo(mediaInfosArr[i]); + break; + } + } + } } } diff --git a/src/streaming/text/TextSourceBuffer.js b/src/streaming/text/TextSourceBuffer.js index a2e827f84e..dfddae13b9 100644 --- a/src/streaming/text/TextSourceBuffer.js +++ b/src/streaming/text/TextSourceBuffer.js @@ -84,7 +84,7 @@ function TextSourceBuffer() { logger = Debug(context).getInstance().getLogger(instance); } - function initialize(type, streamProcessor) { + function initialize(mimeType, streamProcessor) { parser = null; fragmentModel = null; initializationSegmentReceived = false; @@ -101,7 +101,7 @@ function TextSourceBuffer() { videoModel: videoModel }); textTracks.initialize(); - isFragmented = !dashManifestModel.getIsTextTrack(type); + isFragmented = !dashManifestModel.getIsTextTrack(mimeType); boxParser = BoxParser(context).getInstance(); fragmentedTextBoxParser = FragmentedTextBoxParser(context).getInstance(); fragmentedTextBoxParser.setConfig({ @@ -406,7 +406,10 @@ function TextSourceBuffer() { try { result = getParser(codecType).parse(ccContent, 0); - createTextTrackFromMediaInfo(result, mediaInfo); + for (i = 0; i < mediaInfos.length; i++) { + createTextTrackFromMediaInfo(null, mediaInfos[i]); + } + textTracks.addCaptions(textTracks.getCurrentTrackIdx(), 0, result); } catch (e) { errHandler.timedTextError(e, 'parse', ccContent); } From 14cd293fa2efce06f104fc816dfb5790c0112d3c Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Wed, 25 Apr 2018 10:45:48 +0200 Subject: [PATCH 5/8] remove getMimeTypeOrType function --- src/streaming/Stream.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/streaming/Stream.js b/src/streaming/Stream.js index adb803243b..4091f2d2ca 100644 --- a/src/streaming/Stream.js +++ b/src/streaming/Stream.js @@ -256,10 +256,6 @@ function Stream(config) { } } - function getMimeTypeOrType(mediaInfo) { - return mediaInfo.type === Constants.TEXT ? mediaInfo.mimeType : mediaInfo.type; - } - function isMediaSupported(mediaInfo) { const type = mediaInfo.type; let codec, @@ -317,7 +313,7 @@ function Stream(config) { function createStreamProcessor(mediaInfo, allMediaForType, mediaSource, optionalSettings) { let streamProcessor = StreamProcessor(context).create({ - type: getMimeTypeOrType(mediaInfo), + type: mediaInfo.type, mimeType: mediaInfo.mimeType, timelineConverter: timelineConverter, adapter: adapter, From 3345acbc077bb7aaba3afceac90308da9ce6b2d3 Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Wed, 25 Apr 2018 10:49:01 +0200 Subject: [PATCH 6/8] add type 'text' in streamProcessors array --- src/streaming/Stream.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/streaming/Stream.js b/src/streaming/Stream.js index 4091f2d2ca..bf39e9d40e 100644 --- a/src/streaming/Stream.js +++ b/src/streaming/Stream.js @@ -585,14 +585,14 @@ function Stream(config) { let arr = []; let type, - controller; + streamProcessor; for (let i = 0; i < ln; i++) { - controller = streamProcessors[i]; - type = controller.getType(); + streamProcessor = streamProcessors[i]; + type = streamProcessor.getType(); - if (type === Constants.AUDIO || type === Constants.VIDEO || type === Constants.FRAGMENTED_TEXT) { - arr.push(controller); + if (type === Constants.AUDIO || type === Constants.VIDEO || type === Constants.FRAGMENTED_TEXT || type === Constants.TEXT) { + arr.push(streamProcessor); } } From 43788ce5235290f9b66cf3141d9f1b6132542987 Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Wed, 25 Apr 2018 11:40:38 +0200 Subject: [PATCH 7/8] update unit tests --- test/unit/mocks/StreamControllerMock.js | 2 ++ ...eaming.text.NotFragmentedTextBufferController.js | 13 +++++++------ test/unit/streaming.text.TextController.js | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/test/unit/mocks/StreamControllerMock.js b/test/unit/mocks/StreamControllerMock.js index 6db59ccbb3..7313718adb 100644 --- a/test/unit/mocks/StreamControllerMock.js +++ b/test/unit/mocks/StreamControllerMock.js @@ -46,6 +46,8 @@ class StreamControllerMock { setConfig() {} reset() {} + + getActiveStreamProcessors() { return [];} } export default StreamControllerMock; diff --git a/test/unit/streaming.text.NotFragmentedTextBufferController.js b/test/unit/streaming.text.NotFragmentedTextBufferController.js index 922939506e..172738ab1a 100644 --- a/test/unit/streaming.text.NotFragmentedTextBufferController.js +++ b/test/unit/streaming.text.NotFragmentedTextBufferController.js @@ -133,7 +133,7 @@ describe('NotFragmentedTextBufferController', function () { }); describe('Method switchInitData', function () { - it('should append init data to source buffer if data have been cached', function () { + it('should not append init data to source buffer if data have already been cached', function () { let chunk = { bytes: 'initData', quality: 2, @@ -148,19 +148,19 @@ describe('NotFragmentedTextBufferController', function () { notFragmentedTextBufferController.createBuffer(mockMediaInfo); const buffer = notFragmentedTextBufferController.getBuffer().getBuffer(); notFragmentedTextBufferController.switchInitData(chunk.streamId, chunk.representationId); - expect(buffer.chunk).to.equal(chunk.bytes); + expect(buffer.chunk).to.equal(null); }); - it('should trigger INIT_REQUESTED if no init data is cached', function (done) { + it('should trigger TIMED_TEXT_REQUESTED if no init data is cached', function (done) { // reset cache initCache.reset(); let onInitRequest = function () { - eventBus.off(Events.INIT_REQUESTED, onInitRequest); + eventBus.off(Events.TIMED_TEXT_REQUESTED, onInitRequest); done(); }; - eventBus.on(Events.INIT_REQUESTED, onInitRequest, this); + eventBus.on(Events.TIMED_TEXT_REQUESTED, onInitRequest, this); notFragmentedTextBufferController.switchInitData('streamId', 'representationId'); }); @@ -172,7 +172,8 @@ describe('NotFragmentedTextBufferController', function () { let event = { sender: { - getStreamProcessor: function () { return streamProcessorMock; } + getStreamProcessor: function () { return streamProcessorMock; }, + getCurrentRepresentation: function () { return { id: 0}; } } }; diff --git a/test/unit/streaming.text.TextController.js b/test/unit/streaming.text.TextController.js index 96e3d78c14..39714e8e3c 100644 --- a/test/unit/streaming.text.TextController.js +++ b/test/unit/streaming.text.TextController.js @@ -6,6 +6,7 @@ import EventBus from '../../src/core/EventBus'; import Events from '../../src/core/events/Events'; import VideoModelMock from './mocks/VideoModelMock'; +import StreamControllerMock from './mocks/StreamControllerMock'; const expect = require('chai').expect; const context = {}; @@ -16,6 +17,7 @@ const eventBus = EventBus(context).getInstance(); describe('TextController', function () { let videoModelMock = new VideoModelMock(); + let streamControllerMock = new StreamControllerMock(); let textTracks; let textController; @@ -27,7 +29,8 @@ describe('TextController', function () { textController = TextController(context).getInstance(); textController.setConfig({ - videoModel: videoModelMock + videoModel: videoModelMock, + streamController: streamControllerMock }); }); From f7b2cb3bdababfbaf28371429248b2a7c07c565d Mon Sep 17 00:00:00 2001 From: Nicolas ANGOT Date: Wed, 6 Jun 2018 15:17:23 +0200 Subject: [PATCH 8/8] bug fix for AdaptationSet with no Id (optional parameter) --- src/streaming/text/TextController.js | 2 +- src/streaming/text/TextSourceBuffer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/streaming/text/TextController.js b/src/streaming/text/TextController.js index c86c948206..41b4906a66 100644 --- a/src/streaming/text/TextController.js +++ b/src/streaming/text/TextController.js @@ -264,7 +264,7 @@ function TextController() { if (streamProcessor && mediaInfosArr) { for (let i = 0; i < mediaInfosArr.length; i++) { - if (mediaInfosArr[i].lang === currentTrackInfo.lang) { + if (mediaInfosArr[i].index === currentTrackInfo.index && mediaInfosArr[i].lang === currentTrackInfo.lang) { streamProcessor.selectMediaInfo(mediaInfosArr[i]); break; } diff --git a/src/streaming/text/TextSourceBuffer.js b/src/streaming/text/TextSourceBuffer.js index dfddae13b9..dd253fc131 100644 --- a/src/streaming/text/TextSourceBuffer.js +++ b/src/streaming/text/TextSourceBuffer.js @@ -301,7 +301,7 @@ function TextSourceBuffer() { textTrackInfo.captionData = captionData; textTrackInfo.lang = mediaInfo.lang; - textTrackInfo.label = mediaInfo.id; // AdaptationSet id (an unsigned int) + textTrackInfo.label = mediaInfo.id ? mediaInfo.id : mediaInfo.index; // AdaptationSet id (an unsigned int) as it's optionnal parameter, use mediaInfo.index textTrackInfo.index = mediaInfo.index; // AdaptationSet index in manifest textTrackInfo.isTTML = checkTTML(); textTrackInfo.defaultTrack = getIsDefault(mediaInfo);