Skip to content

Commit

Permalink
Separate text parsing and display logic.
Browse files Browse the repository at this point in the history
Closes #796.
Closes #923.

Change-Id: Ifc2017b40a0fb570103f0fed7bc130aa24819e9f
  • Loading branch information
ismena committed Jul 17, 2017
1 parent d70f78b commit c70367d
Show file tree
Hide file tree
Showing 23 changed files with 1,423 additions and 470 deletions.
4 changes: 3 additions & 1 deletion build/types/text
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# All standard text parsing plugins.
# All files related to text parsing and displaying.

+../../lib/text/cue.js
+../../lib/text/mp4_ttml_parser.js
+../../lib/text/mp4_vtt_parser.js
+../../lib/text/simple_text_displayer.js
+../../lib/text/ttml_text_parser.js
+../../lib/text/vtt_text_parser.js
5 changes: 4 additions & 1 deletion externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,8 @@ shakaExtern.AbrConfiguration;
* preferredTextLanguage: string,
* restrictions: shakaExtern.Restrictions,
* playRangeStart: number,
* playRangeEnd: number
* playRangeEnd: number,
* textDisplayFactory: shakaExtern.TextDisplayer.Factory
* }}
*
* @property {shakaExtern.DrmConfiguration} drm
Expand Down Expand Up @@ -637,6 +638,8 @@ shakaExtern.AbrConfiguration;
* @property {number} playRangeEnd
* Optional playback and seek end time in seconds. Defaults to the end of
* the presentation if not provided.
* @property {shakaExtern.TextDisplayer.Factory} textDisplayFactory
* A factory to construct text displayer.
* @exportDoc
*/
shakaExtern.PlayerConfiguration;
65 changes: 64 additions & 1 deletion externs/shaka/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ shakaExtern.TextParser.prototype.parseInit = function(data) {};
* @param {shakaExtern.TextParser.TimeContext} timeContext
* The time information that should be used to adjust the times values
* for each cue.
* @return {!Array.<!TextTrackCue>}
* @return {!Array.<!shaka.text.Cue>}
*
* @exportDoc
*/
Expand All @@ -81,3 +81,66 @@ shakaExtern.TextParser.prototype.parseMedia = function(data, timeContext) {};
* @typedef {function(new:shakaExtern.TextParser)}
*/
shakaExtern.TextParserPlugin;



/**
* An interface for plugins that display text.
*
* @interface
* @extends {shaka.util.IDestroyable}
* @exportDoc
*/
shakaExtern.TextDisplayer = function() {};


/**
* Append given text cues to the list of cues to be displayed.
*
* @param {!Array.<!shaka.text.Cue>} cues
* Text cues to be appended.
*
* @exportDoc
*/
shakaExtern.TextDisplayer.prototype.append = function(cues) {};


/**
* Remove cues in a given time range.
*
* @param {number} start
* @param {number} end
* @return {boolean}
*
* @exportDoc
*/
shakaExtern.TextDisplayer.prototype.remove = function(start, end) {};


/**
* Returns true if text is currently visible.
*
* @return {boolean}
*
* @exportDoc
*/
shakaExtern.TextDisplayer.prototype.isTextVisible = function() {};


/**
* Set text visibility.
*
* @param {boolean} on
*
* @exportDoc
*/
shakaExtern.TextDisplayer.prototype.setTextVisibility = function(on) {};


/**
* A factory for creating a TextDisplayer.
*
* @typedef {function(new:shakaExtern.TextDisplayer)}
* @exportDoc
*/
shakaExtern.TextDisplayer.Factory;
12 changes: 6 additions & 6 deletions lib/media/media_source_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ goog.require('shaka.util.PublicPromise');
* when MediaSource operations fail.
* @param {MediaSource} mediaSource The MediaSource, which must be in the
* 'open' state.
* @param {TextTrack} textTrack The TextTrack to use for subtitles/captions.
* @param {shakaExtern.TextDisplayer} textDisplayer
*
* @struct
* @constructor
* @implements {shaka.util.IDestroyable}
*/
shaka.media.MediaSourceEngine = function(video, mediaSource, textTrack) {
shaka.media.MediaSourceEngine = function(video, mediaSource, textDisplayer) {
goog.asserts.assert(mediaSource.readyState == 'open',
'The MediaSource should be in the \'open\' state.');

Expand All @@ -56,8 +56,8 @@ shaka.media.MediaSourceEngine = function(video, mediaSource, textTrack) {
/** @private {MediaSource} */
this.mediaSource_ = mediaSource;

/** @private {TextTrack} */
this.textTrack_ = textTrack;
/** @private {shakaExtern.TextDisplayer} */
this.textDisplayer_ = textDisplayer;

/** @private {!Object.<shaka.util.ManifestParserUtils.ContentType,
SourceBuffer>} */
Expand Down Expand Up @@ -204,8 +204,8 @@ shaka.media.MediaSourceEngine.prototype.destroy = function() {
this.eventManager_ = null;
this.video_ = null;
this.mediaSource_ = null;
this.textTrack_ = null;
this.textEngine_ = null;
this.textDisplayer_ = null;
this.sourceBuffers_ = {};
if (!COMPILED) {
for (var contentType in this.queues_) {
Expand Down Expand Up @@ -265,7 +265,7 @@ shaka.media.MediaSourceEngine.prototype.init = function(typeConfig) {
*/
shaka.media.MediaSourceEngine.prototype.reinitText = function(mimeType) {
if (!this.textEngine_) {
this.textEngine_ = new shaka.text.TextEngine(this.textTrack_);
this.textEngine_ = new shaka.text.TextEngine(this.textDisplayer_);
}
this.textEngine_.initParser(mimeType);
};
Expand Down
58 changes: 15 additions & 43 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ goog.require('shaka.media.PlayheadObserver');
goog.require('shaka.media.SegmentReference');
goog.require('shaka.media.StreamingEngine');
goog.require('shaka.net.NetworkingEngine');
goog.require('shaka.text.SimpleTextDisplayer');
goog.require('shaka.util.CancelableChain');
goog.require('shaka.util.ConfigUtils');
goog.require('shaka.util.Error');
Expand Down Expand Up @@ -67,8 +68,8 @@ shaka.Player = function(video, opt_dependencyInjector) {
/** @private {HTMLMediaElement} */
this.video_ = video;

/** @private {TextTrack} */
this.textTrack_ = null;
/** @private {shakaExtern.TextDisplayer} */
this.textDisplayer_ = null;

/** @private {shaka.util.EventManager} */
this.eventManager_ = new shaka.util.EventManager();
Expand Down Expand Up @@ -207,16 +208,16 @@ shaka.Player.prototype.destroy = function() {
this.unloadChain_,
this.destroyStreaming_(),
this.eventManager_ ? this.eventManager_.destroy() : null,
this.networkingEngine_ ? this.networkingEngine_.destroy() : null
this.networkingEngine_ ? this.networkingEngine_.destroy() : null,
this.textDisplayer_ ? this.textDisplayer_.destroy() : null
]);

this.video_ = null;
this.textTrack_ = null;
this.textDisplayer_ = null;
this.eventManager_ = null;
this.abrManager_ = null;
this.networkingEngine_ = null;
this.config_ = null;

return p;
}.bind(this));
};
Expand Down Expand Up @@ -494,6 +495,8 @@ shaka.Player.prototype.load = function(manifestUri, opt_startTime,
this.abrManager_ = new abrManagerFactory();
this.abrManager_.configure(this.config_.abr);

this.textDisplayer_ = new this.config_.textDisplayFactory();

goog.asserts.assert(this.networkingEngine_, 'Must not be destroyed');
return shaka.media.ManifestParser.getFactory(
manifestUri,
Expand Down Expand Up @@ -561,7 +564,6 @@ shaka.Player.prototype.load = function(manifestUri, opt_startTime,
this.drmEngine_.configure(this.config_.drm);
return this.drmEngine_.init(manifest, false /* isOffline */);
}.bind(this)).then(function() {

// Re-filter the manifest after DRM has been initialized.
this.manifest_.periods.forEach(this.filterPeriod_.bind(this));

Expand Down Expand Up @@ -604,7 +606,6 @@ shaka.Player.prototype.load = function(manifestUri, opt_startTime,
]);
}.bind(this)).then(function() {
this.abrManager_.init(this.switch_.bind(this));

// MediaSource is open, so create the Playhead, MediaSourceEngine, and
// StreamingEngine.
var startTime = opt_startTime || this.config_.playRangeStart;
Expand All @@ -618,7 +619,6 @@ shaka.Player.prototype.load = function(manifestUri, opt_startTime,
// If the content is multi-codec and the browser can play more than one of
// them, choose codecs now before we initialize streaming.
this.chooseCodecsAndFilterManifest_();

return this.streamingEngine_.init();
}.bind(this)).then(function() {
if (this.config_.streaming.startAtSegmentBoundary) {
Expand Down Expand Up @@ -821,7 +821,7 @@ shaka.Player.prototype.createMediaSource = function() {
*/
shaka.Player.prototype.createMediaSourceEngine = function() {
return new shaka.media.MediaSourceEngine(
this.video_, this.mediaSource_, this.textTrack_);
this.video_, this.mediaSource_, this.textDisplayer_);
};


Expand Down Expand Up @@ -1432,7 +1432,7 @@ shaka.Player.prototype.selectTextLanguage = function(language, opt_role) {
* @export
*/
shaka.Player.prototype.isTextTrackVisible = function() {
return this.textTrack_.mode == 'showing';
return this.textDisplayer_.isTextVisible();
};


Expand All @@ -1443,7 +1443,7 @@ shaka.Player.prototype.isTextTrackVisible = function() {
* @export
*/
shaka.Player.prototype.setTextTrackVisibility = function(on) {
this.textTrack_.mode = on ? 'showing' : 'hidden';
this.textDisplayer_.setTextVisibility(on);
this.onTextTrackVisibility_();
};

Expand Down Expand Up @@ -1662,30 +1662,6 @@ shaka.Player.prototype.initialize_ = function() {
// Start the (potentially slow) process of opening MediaSource now.
this.mediaSourceOpen_ = this.createMediaSource();

// If the video element has TextTracks, disable them. If we see one that
// was created by a previous instance of Shaka Player, reuse it.
for (var i = 0; i < this.video_.textTracks.length; ++i) {
var track = this.video_.textTracks[i];
track.mode = 'disabled';

if (track.label == shaka.Player.TextTrackLabel_) {
this.textTrack_ = track;
}
}

if (!this.textTrack_) {
// As far as I can tell, there is no observable difference between setting
// kind to 'subtitles' or 'captions' when creating the TextTrack object.
// The individual text tracks from the manifest will still have their own
// kinds which can be displayed in the app's UI.
this.textTrack_ = this.video_.addTextTrack(
'subtitles', shaka.Player.TextTrackLabel_);
}
this.textTrack_.mode = 'hidden';

// TODO: test that in all cases, the built-in CC controls in the video element
// are toggling our TextTrack.

// Listen for video errors.
this.eventManager_.listen(this.video_, 'error',
this.onVideoError_.bind(this));
Expand Down Expand Up @@ -1831,13 +1807,6 @@ shaka.Player.prototype.resetStreaming_ = function() {
};


/**
* @const {string}
* @private
*/
shaka.Player.TextTrackLabel_ = 'Shaka Player TextTrack';


/**
* @return {!Object}
* @private
Expand Down Expand Up @@ -1904,6 +1873,9 @@ shaka.Player.prototype.defaultConfig_ = function() {
jumpLargeGaps: false
},
abrFactory: shaka.abr.SimpleAbrManager,
textDisplayFactory: function(videoElement) {
return new shaka.text.SimpleTextDisplayer(videoElement);
}.bind(null, this.video_),
abr: {
enabled: true,
// This is a relatively safe default, since 3G cell connections
Expand Down Expand Up @@ -2355,7 +2327,7 @@ shaka.Player.prototype.chooseStreamsAndSwitch_ = function(period) {
languageMatches[ContentType.TEXT] &&
chosen[ContentType.TEXT].language !=
chosen[ContentType.AUDIO].language) {
this.textTrack_.mode = 'showing';
this.textDisplayer_.setTextVisibility(true);
this.onTextTrackVisibility_();
}
}
Expand Down
Loading

0 comments on commit c70367d

Please sign in to comment.