diff --git a/demo/info_section.js b/demo/info_section.js index 249da17406..f65ff5102a 100644 --- a/demo/info_section.js +++ b/demo/info_section.js @@ -107,17 +107,19 @@ shakaDemo.updateTrackOptions_ = function(list, tracks, language) { variant: function(track) { var trackInfo = ''; if (track.language) trackInfo += 'language: ' + track.language + ', '; + if (track.label) trackInfo += 'label: ' + track.label + ', '; if (track.width && track.height) trackInfo += track.width + 'x' + track.height + ', '; trackInfo += track.bandwidth + ' bits/s'; return trackInfo; - }, + } , text: function(track) { - return 'language: ' + track.language + ' ' + - '(' + track.kind + ')'; + var trackInfo = 'language: ' + track.language + ', '; + if (track.label) trackInfo += 'label: ' + track.label + ', '; + trackInfo += 'kind: ' + track.kind; + return trackInfo; } }; - // Remove old tracks while (list.firstChild) { list.removeChild(list.firstChild); diff --git a/externs/shaka/manifest.js b/externs/shaka/manifest.js index e165893ea7..f9f58c74a1 100644 --- a/externs/shaka/manifest.js +++ b/externs/shaka/manifest.js @@ -297,6 +297,7 @@ shakaExtern.GetSegmentReferenceFunction; * encrypted: boolean, * keyId: ?string, * language: string, + * label: ?string, * type: string, * primary: boolean, * trickModeVideo: ?shakaExtern.Stream, @@ -371,6 +372,8 @@ shakaExtern.GetSegmentReferenceFunction; * The Stream's language, specified as a language code.
* Audio stream's language must be identical to the language of the containing * Variant. + * @property {?string} label + * The Stream's label, unique text that should describe the audio/text track. * @property {string} type * Required.
* Content type (e.g. 'video', 'audio' or 'text') diff --git a/externs/shaka/offline.js b/externs/shaka/offline.js index 0b600a9776..16151ffd7a 100644 --- a/externs/shaka/offline.js +++ b/externs/shaka/offline.js @@ -148,6 +148,7 @@ shakaExtern.PeriodDB; * frameRate: (number|undefined), * kind: (string|undefined), * language: string, + * label: ?string, * width: ?number, * height: ?number, * initSegmentUri: ?string, @@ -175,6 +176,8 @@ shakaExtern.PeriodDB; * The kind of text stream; undefined for audio/video. * @property {string} language * The language of the stream; '' for video. + * @property {?string} label + * The label of the stream; '' for video. * @property {?number} width * The width of the stream; null for audio/text. * @property {?number} height diff --git a/externs/shaka/player.js b/externs/shaka/player.js index df0a3597f7..73bc9abcc1 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -130,6 +130,7 @@ shakaExtern.Stats; * bandwidth: number, * * language: string, + * label: ?string, * kind: ?string, * width: ?number, * height: ?number, @@ -161,6 +162,8 @@ shakaExtern.Stats; * @property {string} language * The language of the track, or 'und' if not given. This is the exact * value provided in the manifest; it may need to be normalized. + * @property {?string} label + * The track label, unique text that should describe the track. * @property {?string} kind * (only for text tracks) The kind of text track, either 'caption' or * 'subtitle'. diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index ec494c552d..c881808e6f 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -957,11 +957,14 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) { var language = shaka.util.LanguageUtils.normalize(elem.getAttribute('lang') || 'und'); + // non-standard attribute(yet) supported by Kaltura + var label = elem.getAttribute('label'); + // Parse Representations into Streams. var representations = XmlUtils.findChildren(elem, 'Representation'); var streams = representations .map(this.parseRepresentation_.bind( - this, context, contentProtection, kind, language, main)) + this, context, contentProtection, kind, language, label, main)) .filter(function(s) { return !!s; }); if (streams.length == 0) { @@ -1018,6 +1021,7 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) { * @param {shaka.dash.ContentProtection.Context} contentProtection * @param {(string|undefined)} kind * @param {string} language + * @param {string} label * @param {boolean} isPrimary * @param {!Element} node * @return {?shakaExtern.Stream} The Stream, or null when there is a @@ -1026,7 +1030,7 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) { * @private */ shaka.dash.DashParser.prototype.parseRepresentation_ = function( - context, contentProtection, kind, language, isPrimary, node) { + context, contentProtection, kind, language, label, isPrimary, node) { var XmlUtils = shaka.util.XmlUtils; var ContentType = shaka.util.ManifestParserUtils.ContentType; @@ -1105,6 +1109,7 @@ shaka.dash.DashParser.prototype.parseRepresentation_ = function( encrypted: contentProtection.drmInfos.length > 0, keyId: keyId, language: language, + label: label, type: context.adaptationSet.contentType, primary: isPrimary, trickModeVideo: null, diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 044636c7f7..0b99342c2a 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -500,6 +500,9 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromMediaTag_ = var LanguageUtils = shaka.util.LanguageUtils; var language = LanguageUtils.normalize(/** @type {string} */( tag.getAttributeValue('LANGUAGE', 'und'))); + var labelValue = tag.getAttributeValue('NAME'); + var label = labelValue ? labelValue.toString() : null; + var defaultAttr = tag.getAttribute('DEFAULT'); var autoselectAttr = tag.getAttribute('AUTOSELECT'); @@ -511,7 +514,7 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromMediaTag_ = var uri = HlsParser.getRequiredAttributeValue_(tag, 'URI'); var primary = !!defaultAttr || !!autoselectAttr; return this.createStreamInfo_(uri, allCodecs, type, timeOffset, language, - primary).then(function(streamInfo) { + primary, label).then(function(streamInfo) { this.mediaTagsToStreamInfosMap_[tag.id] = streamInfo; return streamInfo; }.bind(this)); @@ -535,7 +538,8 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromVariantTag_ = var uri = shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'URI'); return this.createStreamInfo_(uri, allCodecs, type, timeOffset, - /* language */ 'und', /* primary */ false); + /* language */ 'und', /* primary */ false, + null); }; @@ -546,12 +550,13 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromVariantTag_ = * @param {?number} timeOffset * @param {!string} language * @param {boolean} primary + * @param {?string} label * @return {!Promise.} * @throws shaka.util.Error * @private */ shaka.hls.HlsParser.prototype.createStreamInfo_ = - function(uri, allCodecs, type, timeOffset, language, primary) { + function(uri, allCodecs, type, timeOffset, language, primary, label) { var Utils = shaka.hls.Utils; var ContentType = shaka.util.ManifestParserUtils.ContentType; var HlsParser = shaka.hls.HlsParser; @@ -663,6 +668,7 @@ shaka.hls.HlsParser.prototype.createStreamInfo_ = encrypted: encrypted, keyId: keyId, language: language, + label: label || null, type: type, primary: primary, // TODO: trick mode diff --git a/lib/offline/offline_utils.js b/lib/offline/offline_utils.js index 45e4a5b7d3..faa6b2404c 100644 --- a/lib/offline/offline_utils.js +++ b/lib/offline/offline_utils.js @@ -251,6 +251,7 @@ shaka.offline.OfflineUtils.createStream_ = function(streamDb) { encrypted: streamDb.encrypted, keyId: streamDb.keyId, language: streamDb.language, + label: streamDb.label || null, type: streamDb.contentType, primary: streamDb.primary, trickModeVideo: null, diff --git a/lib/offline/storage.js b/lib/offline/storage.js index 0e268de0da..33a86f6a2d 100644 --- a/lib/offline/storage.js +++ b/lib/offline/storage.js @@ -883,6 +883,7 @@ shaka.offline.Storage.prototype.createStream_ = function( frameRate: stream.frameRate, kind: stream.kind, language: stream.language, + label: stream.label, width: stream.width || null, height: stream.height || null, initSegmentUri: initUri, diff --git a/lib/player.js b/lib/player.js index a84d29aaec..076a7d3914 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1411,11 +1411,12 @@ shaka.Player.prototype.getStats = function() { * @param {string} kind * @param {string} mime * @param {string=} opt_codec + * @param {string=} opt_label * @return {!Promise.} * @export */ shaka.Player.prototype.addTextTrack = function( - uri, language, kind, mime, opt_codec) { + uri, language, kind, mime, opt_codec, opt_label) { if (!this.streamingEngine_) { shaka.log.error( 'Must call load() and wait for it to resolve before adding text ' + @@ -1466,6 +1467,7 @@ shaka.Player.prototype.addTextTrack = function( encrypted: false, keyId: null, language: language, + label: opt_label || null, type: ContentType.TEXT, primary: false, trickModeVideo: null, @@ -1494,6 +1496,7 @@ shaka.Player.prototype.addTextTrack = function( type: ContentType.TEXT, bandwidth: 0, language: language, + label: opt_label || null, kind: kind, width: null, height: null diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js index 3fc7f47332..cb470d60a7 100644 --- a/lib/util/stream_utils.js +++ b/lib/util/stream_utils.js @@ -219,6 +219,7 @@ shaka.util.StreamUtils.getVariantTracks = function(period, activeAudioId, activeVideoId) { var StreamUtils = shaka.util.StreamUtils; var variants = StreamUtils.getPlayableVariants(period.variants); + var label = null; var tracks = variants.map(function(variant) { var isActive; if (variant.video && variant.audio) { @@ -233,6 +234,7 @@ shaka.util.StreamUtils.getVariantTracks = if (variant.audio) { if (codecs != '') codecs += ', '; codecs += variant.audio.codecs; + label = variant.audio.label; } var audioCodec = variant.audio ? variant.audio.codecs : null; @@ -251,6 +253,7 @@ shaka.util.StreamUtils.getVariantTracks = type: 'variant', bandwidth: variant.bandwidth, language: variant.language, + label: label, kind: kind || null, width: variant.video ? variant.video.width : null, height: variant.video ? variant.video.height : null, diff --git a/test/dash/dash_parser_manifest_unit.js b/test/dash/dash_parser_manifest_unit.js index 70c85ce2be..5b9b833ac0 100644 --- a/test/dash/dash_parser_manifest_unit.js +++ b/test/dash/dash_parser_manifest_unit.js @@ -119,7 +119,7 @@ describe('DashParser Manifest', function() { ' ', ' ', ' ', + ' lang="es" label="spanish">', ' ', ' ', ' ', @@ -176,6 +176,7 @@ describe('DashParser Manifest', function() { .primary() .addTextStream(jasmine.any(Number)) .language('es') + .label('spanish') .primary() .anySegmentFunctions() .anyInitSegment() diff --git a/test/offline/offline_utils_unit.js b/test/offline/offline_utils_unit.js index 85e3048a0b..bd411bd03a 100644 --- a/test/offline/offline_utils_unit.js +++ b/test/offline/offline_utils_unit.js @@ -46,7 +46,6 @@ describe('OfflineUtils', function() { startTime: 60, streams: [createVideoStreamDb(1), createAudioStreamDb(2)] }; - var period = OfflineUtils.reconstructPeriod(periodDb, drmInfos, timeline); expect(period).toBeTruthy(); expect(period.startTime).toBe(periodDb.startTime); @@ -152,6 +151,7 @@ describe('OfflineUtils', function() { frameRate: 22, kind: undefined, language: '', + label: null, width: 250, height: 100, initSegmentUri: null, @@ -183,6 +183,7 @@ describe('OfflineUtils', function() { frameRate: undefined, kind: undefined, language: 'en', + label: null, width: null, height: null, initSegmentUri: 'offline:1/' + id + '/0', @@ -213,6 +214,7 @@ describe('OfflineUtils', function() { frameRate: undefined, kind: undefined, language: 'en', + label: null, width: null, height: null, initSegmentUri: 'offline:1/' + id + '/0', @@ -255,6 +257,7 @@ describe('OfflineUtils', function() { encrypted: streamDb.encrypted, keyId: streamDb.keyId, language: streamDb.language, + label: streamDb.label, type: streamDb.contentType, primary: streamDb.primary, trickModeVideo: null, diff --git a/test/offline/storage_unit.js b/test/offline/storage_unit.js index 404afd3b83..be13b09b16 100644 --- a/test/offline/storage_unit.js +++ b/test/offline/storage_unit.js @@ -133,6 +133,7 @@ describe('Storage', function() { type: 'variant', bandwidth: 0, language: 'en', + label: null, kind: null, width: 1920, height: 1080, diff --git a/test/player_unit.js b/test/player_unit.js index 3351931c40..4119fa1d33 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -784,6 +784,7 @@ describe('Player', function() { type: 'variant', bandwidth: 200, language: 'en', + label: null, kind: null, width: 100, height: 200, @@ -800,6 +801,7 @@ describe('Player', function() { type: 'variant', bandwidth: 300, language: 'en', + label: null, kind: null, width: 200, height: 400, @@ -816,6 +818,7 @@ describe('Player', function() { type: 'variant', bandwidth: 200, language: 'en', + label: null, kind: null, width: 100, height: 200, @@ -832,6 +835,7 @@ describe('Player', function() { type: 'variant', bandwidth: 300, language: 'en', + label: null, kind: null, width: 200, height: 400, @@ -848,6 +852,7 @@ describe('Player', function() { type: 'variant', bandwidth: 300, language: 'es', + label: null, kind: null, width: 200, height: 400, diff --git a/test/test/util/manifest_generator.js b/test/test/util/manifest_generator.js index 97a15372fa..9dd7ab2d5b 100644 --- a/test/test/util/manifest_generator.js +++ b/test/test/util/manifest_generator.js @@ -162,6 +162,18 @@ shaka.test.ManifestGenerator.prototype.language = function(language) { }; +/** + * Sets the label of the language of the most recent variant or text stream. + * + * @param {string} label + * @return {!shaka.test.ManifestGenerator} + */ +shaka.test.ManifestGenerator.prototype.label = function(label) { + this.currentStream_().label = label; + return this; +}; + + /** * Sets that the most recent variant or text stream is primary. * @@ -456,6 +468,7 @@ shaka.test.ManifestGenerator.prototype.createStream_ = encrypted: false, keyId: null, language: language, + label: null, type: type, primary: false, trickModeVideo: null,