Skip to content
This repository was archived by the owner on Oct 20, 2022. It is now read-only.

Commit 0ca6901

Browse files
committed
Merge branch 'release/1.14.2'
2 parents bd401e6 + ce55e54 commit 0ca6901

File tree

12 files changed

+132
-57
lines changed

12 files changed

+132
-57
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ addons:
55
browserstack:
66
username: "bertrandberthelo1"
77
access_key:
8-
secure: "kB8iXiydT+xheyHox2zwq/1k75uUmF+F2b9k76Nhbb001Mh5608kzhH9xXFM+BUyM1pm3LImF+vYcSfKMYlDn/KBB7s9p8TJfwC/obbmtWJucSjtRiVo9aOOa7Ox2M+ACb0rsLpvzFRiHtYo0HZNFVkIfvqZN389Imm6UCOXsyo="
8+
secure: "FSJvfvEX6C4OAM6ZF/bQdS718N/IOCeErBljObyWlJ6NoLakIsIp9ssYiNcVQHtUdTuuHOuIdLxjPqMoxQkZtoHS2oZ1wg7veaN/wl+5HuxeaOvHxahNlxT7Z0FzQgxiHDFTHsXP2a+vDtEGjCIdvvcurR/2cK2gkfSFJ5NeeXY="
99
branches:
1010
only:
1111
- master

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ function onPlayBitrateChanged(e) {
183183

184184
## Documentation
185185

186-
Full [API Documentation](http://orange-opensource.github.io/hasplayer.js/development/doc/index.html) is available describing MediaPlayer public methods and events.
186+
Full [API Documentation](http://orange-opensource.github.io/hasplayer.js/development/doc/jsdoc/index.html) is available describing MediaPlayer public methods and events.
187187

188188
This API documentation can be generated using following gulp command:
189189
```

RELEASES NOTES.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
### Release Notes v1.14.2 (2018/04/09)
2+
* Bugs fixing:
3+
* - Fix reset process for protected streams (patch for MediaKeySession.close()) [#225]
4+
* - Fix bug when configuring robustness rules for key system access [#224]
5+
* - [MSS] Correct support for specific timescales (at <SmoothStreamingMedia> and <StreamIndex> levels) [#229, #230]
6+
* - [MSS] Correct 'subs' box writing [#231]
7+
* - [HLS] Correct start time support in case of HLS native playback on Safari [#223]
8+
19
### Release Notes v1.14.1 (2018/02/15)
210
* Bugs fixing:
311
* - [HLS] Correct key error ('webkitkeyerror') handler (native HLS+FP on Safari/OSx use case)

app/js/hls/HlsStream.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,9 @@ Hls.dependencies.HlsStream = function() {
488488
},
489489

490490
load: function(url) {
491+
if (initialStartTime >= 0) {
492+
url += '#t=' + initialStartTime;
493+
}
491494
this.videoModel.setSource(url);
492495
},
493496

app/js/mss/MssParser.js

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ if (!Number.MAX_SAFE_INTEGER) {
2222
Mss.dependencies.MssParser = function() {
2323
"use strict";
2424

25-
var TIME_SCALE_100_NANOSECOND_UNIT = 10000000.0,
25+
var DEFAULT_TIME_SCALE = 10000000.0,
2626
SUPPORTED_CODECS = ["AAC", "AACL", "AVC1", "H264", "TTML", "DFXP"],
2727
samplingFrequencyIndex = {
2828
96000: 0x0,
@@ -47,7 +47,7 @@ Mss.dependencies.MssParser = function() {
4747
xmlDoc = null,
4848
baseURL = null,
4949

50-
mapPeriod = function() {
50+
mapPeriod = function(timescale) {
5151
var period = {},
5252
adaptations = [],
5353
adaptation,
@@ -59,7 +59,7 @@ Mss.dependencies.MssParser = function() {
5959
// For each StreamIndex node, create an AdaptationSet element
6060
for (i = 0; i < smoothNode.childNodes.length; i++) {
6161
if (smoothNode.childNodes[i].nodeName === "StreamIndex") {
62-
adaptation = mapAdaptationSet.call(this, smoothNode.childNodes[i]);
62+
adaptation = mapAdaptationSet.call(this, smoothNode.childNodes[i], timescale);
6363
if (adaptation !== null) {
6464
adaptations.push(adaptation);
6565
}
@@ -74,7 +74,7 @@ Mss.dependencies.MssParser = function() {
7474
return period;
7575
},
7676

77-
mapAdaptationSet = function(streamIndex) {
77+
mapAdaptationSet = function(streamIndex, timescale) {
7878

7979
var adaptationSet = {},
8080
representations = [],
@@ -98,7 +98,7 @@ Mss.dependencies.MssParser = function() {
9898
}
9999

100100
// Create a SegmentTemplate with a SegmentTimeline
101-
segmentTemplate = mapSegmentTemplate.call(this, streamIndex);
101+
segmentTemplate = mapSegmentTemplate.call(this, streamIndex, timescale);
102102

103103
qualityLevels = this.domParser.getChildNodes(streamIndex, "QualityLevel");
104104
// For each QualityLevel node, create a Representation element
@@ -265,23 +265,27 @@ Mss.dependencies.MssParser = function() {
265265
return "mp4a.40." + objectType;
266266
},
267267

268-
mapSegmentTemplate = function(streamIndex) {
268+
mapSegmentTemplate = function(streamIndex, timescale) {
269269

270270
var segmentTemplate = {},
271-
mediaUrl;
271+
mediaUrl,
272+
streamIndexTimeScale;
272273

273274
mediaUrl = this.domParser.getAttributeValue(streamIndex, "Url").replace('{bitrate}', '$Bandwidth$');
274275
mediaUrl = mediaUrl.replace('{start time}', '$Time$');
275276

277+
streamIndexTimeScale = this.domParser.getAttributeValue(streamIndex, "TimeScale");
278+
streamIndexTimeScale = streamIndexTimeScale ? parseFloat(streamIndexTimeScale) : timescale;
279+
276280
segmentTemplate.media = mediaUrl;
277-
segmentTemplate.timescale = TIME_SCALE_100_NANOSECOND_UNIT;
281+
segmentTemplate.timescale = streamIndexTimeScale;
278282

279-
segmentTemplate.SegmentTimeline = mapSegmentTimeline.call(this, streamIndex);
283+
segmentTemplate.SegmentTimeline = mapSegmentTimeline.call(this, streamIndex, segmentTemplate.timescale);
280284

281285
return segmentTemplate;
282286
},
283287

284-
mapSegmentTimeline = function(streamIndex) {
288+
mapSegmentTimeline = function(streamIndex, timescale) {
285289

286290
var segmentTimeline = {},
287291
chunks = this.domParser.getChildNodes(streamIndex, "c"),
@@ -361,7 +365,7 @@ Mss.dependencies.MssParser = function() {
361365

362366
segmentTimeline.S = segments;
363367
segmentTimeline.S_asArray = segments;
364-
segmentTimeline.duration = duration / TIME_SCALE_100_NANOSECOND_UNIT;
368+
segmentTimeline.duration = duration / timescale;
365369

366370
return segmentTimeline;
367371
},
@@ -559,22 +563,24 @@ Mss.dependencies.MssParser = function() {
559563
// Set mpd node properties
560564
mpd.name = 'MSS';
561565
mpd.profiles = "urn:mpeg:dash:profile:isoff-live:2011";
566+
var timescale = this.domParser.getAttributeValue(smoothNode, 'TimeScale');
567+
mpd.timescale = timescale ? parseFloat(timescale) : DEFAULT_TIME_SCALE;
562568
var isLive = this.domParser.getAttributeValue(smoothNode, 'IsLive');
563569
mpd.type = (isLive !== null && isLive.toLowerCase() === 'true') ? 'dynamic' : 'static';
564-
mpd.timeShiftBufferDepth = parseFloat(this.domParser.getAttributeValue(smoothNode, 'DVRWindowLength')) / TIME_SCALE_100_NANOSECOND_UNIT;
570+
mpd.timeShiftBufferDepth = parseFloat(this.domParser.getAttributeValue(smoothNode, 'DVRWindowLength')) / mpd.timescale;
565571
var duration = parseFloat(this.domParser.getAttributeValue(smoothNode, 'Duration'));
566572

567573
// If live manifest with Duration, we consider it as a start-over manifest
568574
if (mpd.type === "dynamic" && duration > 0) {
569575
mpd.type = "static";
570576
mpd.startOver = true;
571577
// We set timeShiftBufferDepth to initial duration, to be used by MssFragmentController to update segment timeline
572-
mpd.timeShiftBufferDepth = duration / TIME_SCALE_100_NANOSECOND_UNIT;
578+
mpd.timeShiftBufferDepth = duration / mpd.timescale;
573579
// Duration will be set according to current segment timeline duration (see below)
574580
}
575581

576582
// Complete manifest/mpd initialization
577-
mpd.mediaPresentationDuration = (duration === 0) ? Infinity : (duration / TIME_SCALE_100_NANOSECOND_UNIT);
583+
mpd.mediaPresentationDuration = (duration === 0) ? Infinity : (duration / mpd.timescale);
578584
mpd.BaseURL = baseURL;
579585
mpd.minBufferTime = MediaPlayer.dependencies.BufferExtensions.DEFAULT_MIN_BUFFER_TIME;
580586

@@ -584,7 +590,7 @@ Mss.dependencies.MssParser = function() {
584590
}
585591

586592
// Map period node to manifest root node
587-
mpd.Period = mapPeriod.call(this);
593+
mpd.Period = mapPeriod.call(this, mpd.timescale);
588594
mpd.Period_asArray = [mpd.Period];
589595

590596
period = mpd.Period;
@@ -674,7 +680,7 @@ Mss.dependencies.MssParser = function() {
674680
for (i = 0; i < adaptations.length; i++) {
675681
if (adaptations[i].contentType === 'audio' || adaptations[i].contentType === 'video') {
676682
segments = adaptations[i].SegmentTemplate.SegmentTimeline.S_asArray;
677-
startTime = segments[0].t;
683+
startTime = segments[0].t / adaptations[i].SegmentTemplate.timescale;
678684
if (timestampOffset === undefined) {
679685
timestampOffset = startTime;
680686
}
@@ -695,13 +701,13 @@ Mss.dependencies.MssParser = function() {
695701
if (!segments[j].tManifest) {
696702
segments[j].tManifest = segments[j].t;
697703
}
698-
segments[j].t -= timestampOffset;
704+
segments[j].t -= (timestampOffset * adaptations[i].SegmentTemplate.timescale);
699705
}
700706
if (adaptations[i].contentType === 'audio' || adaptations[i].contentType === 'video') {
701707
period.start = Math.max(segments[0].t, period.start);
702708
}
703709
}
704-
period.start /= TIME_SCALE_100_NANOSECOND_UNIT;
710+
period.start /= mpd.timescale;
705711
}
706712
}
707713

app/js/streaming/MediaPlayer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,9 @@ MediaPlayer = function () {
11411141
*/
11421142
getVideoBitrates: function () {
11431143
_isPlayerInitialized();
1144+
if (!videoBitrates) {
1145+
return [];
1146+
}
11441147
return videoBitrates.slice();
11451148
},
11461149

app/js/streaming/MetricsExtensions.js

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ MediaPlayer.dependencies.MetricsExtensions = function() {
104104
i = 0,
105105
adaptation;
106106

107+
if (!manifest) {
108+
return null;
109+
}
110+
107111
for (i = 0; i < manifest.Period.AdaptationSet.length; i++) {
108112
adaptation = manifest.Period.AdaptationSet[i];
109113
if (adaptation.type === type) {
@@ -120,6 +124,10 @@ MediaPlayer.dependencies.MetricsExtensions = function() {
120124
i = 0,
121125
adaptation;
122126

127+
if (!manifest) {
128+
return null;
129+
}
130+
123131
for (i = 0; i < manifest.Period.AdaptationSet.length; i++) {
124132
adaptation = manifest.Period.AdaptationSet[i];
125133
if (adaptation.type === type || adaptation.contentType === type) {
@@ -137,19 +145,16 @@ MediaPlayer.dependencies.MetricsExtensions = function() {
137145
representation,
138146
periodArray;
139147

140-
if (manifest) {
141-
periodArray = manifest.Period_asArray;
142-
143-
representation = findRepresentionInPeriodArray.call(self, periodArray, representationId);
144-
145-
if (representation === null) {
146-
return null;
147-
}
148+
if (!manifest) {
149+
return null;
150+
}
148151

149-
return representation.width;
150-
} else {
152+
periodArray = manifest.Period_asArray;
153+
representation = findRepresentionInPeriodArray.call(self, periodArray, representationId);
154+
if (representation === null) {
151155
return null;
152156
}
157+
return representation.width;
153158
};
154159

155160
rslt.getVideoHeightForRepresentation = function(representationId) {
@@ -158,19 +163,16 @@ MediaPlayer.dependencies.MetricsExtensions = function() {
158163
representation,
159164
periodArray;
160165

161-
if (manifest) {
162-
periodArray = manifest.Period_asArray;
163-
164-
representation = findRepresentionInPeriodArray.call(self, periodArray, representationId);
165-
166-
if (representation === null) {
167-
return null;
168-
}
166+
if (!manifest) {
167+
return null;
168+
}
169169

170-
return representation.height;
171-
} else {
170+
periodArray = manifest.Period_asArray;
171+
representation = findRepresentionInPeriodArray.call(self, periodArray, representationId);
172+
if (representation === null) {
172173
return null;
173174
}
175+
return representation.height;
174176
};
175177

176178
rslt.getCodecsForRepresentation = function(representationId) {
@@ -179,12 +181,14 @@ MediaPlayer.dependencies.MetricsExtensions = function() {
179181
representation,
180182
periodArray = manifest.Period_asArray;
181183

182-
representation = findRepresentionInPeriodArray.call(self, periodArray, representationId);
184+
if (!manifest) {
185+
return null;
186+
}
183187

188+
representation = findRepresentionInPeriodArray.call(self, periodArray, representationId);
184189
if (representation === null) {
185190
return null;
186191
}
187-
188192
return representation.codecs;
189193
};
190194

@@ -213,7 +217,7 @@ MediaPlayer.dependencies.MetricsExtensions = function() {
213217
representationArrayIndex,
214218
bitrateArray = [];
215219

216-
if (((manifest === null) || (manifest === undefined)) && ((data === null) || (data === undefined))) {
220+
if (!manifest) {
217221
return null;
218222
}
219223

@@ -262,7 +266,7 @@ MediaPlayer.dependencies.MetricsExtensions = function() {
262266
representationArrayIndex,
263267
bitrateArray = [];
264268

265-
if ((manifest === null) || (manifest === undefined)) {
269+
if (!manifest) {
266270
return null;
267271
}
268272

app/js/streaming/StreamController.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ MediaPlayer.dependencies.StreamController = function() {
404404
stream.setDefaultAudioLang(defaultAudioLang);
405405
stream.setDefaultSubtitleLang(defaultSubtitleLang);
406406
stream.enableSubtitles(subtitlesEnabled);
407+
stream.setInitialStartTime(source.startTime);
407408
streams.push(stream);
408409
activeStream = stream;
409410
attachVideoEvents.call(this, activeStream.getVideoModel());

app/js/streaming/protection/ProtectionModel_21Jan2015.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ MediaPlayer.models.ProtectionModel_21Jan2015 = function () {
293293
var session,
294294
nbSessions = sessions.length,
295295
i,
296+
closeTimeout,
296297
self = this;
297298

298299
this.debug.log("[DRM][PM_21Jan2015] Teardown");
@@ -305,9 +306,15 @@ MediaPlayer.models.ProtectionModel_21Jan2015 = function () {
305306
removeSession(session);
306307
if (i >= (nbSessions - 1)) {
307308
mediaKeys = null;
309+
clearTimeout(closeTimeout);
308310
self.notify(MediaPlayer.models.ProtectionModel.eventList.ENAME_TEARDOWN_COMPLETE);
309311
}
310312
};
313+
var close = function () {
314+
for (i = 0; i < nbSessions; i++) {
315+
done(sessions[i]);
316+
}
317+
};
311318

312319
if (nbSessions === 0) {
313320
mediaKeys = null;
@@ -329,6 +336,9 @@ MediaPlayer.models.ProtectionModel_21Jan2015 = function () {
329336
});
330337
})(session);
331338
}
339+
// Patch for MediaKeySession.close() that may never resolve returned promise
340+
// (for example after license request failure)
341+
closeTimeout = setTimeout(close, 1000);
332342
} else {
333343
// If license persistence is enabled, then keep usable sessions data and MediaKeys instance
334344
for (i = 0; i < sessions.length; i++) {

app/js/streaming/protection/drm/KeySystem_Widevine.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ MediaPlayer.dependencies.protection.KeySystem_Widevine = function() {
4040

4141
var keySystemStr = "com.widevine.alpha",
4242
keySystemUUID = "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
43-
protData = null,
43+
protData,
4444

4545
doGetInitData = function(cpData) {
4646
return MediaPlayer.dependencies.protection.CommonEncryption.parseInitDataFromContentProtection(cpData);
@@ -49,10 +49,10 @@ MediaPlayer.dependencies.protection.KeySystem_Widevine = function() {
4949
doGetKeySystemConfigurations = function(videoCodec, audioCodec, sessionType) {
5050
var ksConfigurations = MediaPlayer.dependencies.protection.CommonEncryption.getKeySystemConfigurations(videoCodec, audioCodec, sessionType);
5151
if (protData) {
52-
if (protData.audioRobustness) {
52+
if (protData.audioRobustness && ksConfigurations[0].audioCapabilities.length > 0) {
5353
ksConfigurations[0].audioCapabilities[0].robustness = protData.audioRobustness;
5454
}
55-
if (protData.videoRobustness) {
55+
if (protData.videoRobustness && ksConfigurations[0].videoCapabilities.length > 0) {
5656
ksConfigurations[0].videoCapabilities[0].robustness = protData.videoRobustness;
5757
}
5858
}
@@ -74,11 +74,9 @@ MediaPlayer.dependencies.protection.KeySystem_Widevine = function() {
7474
sessionType: "temporary",
7575

7676
init: function(protectionData) {
77-
if (protectionData) {
78-
protData = protectionData;
79-
if (protData.sessionType) {
80-
this.sessionType = protData.sessionType;
81-
}
77+
protData = protectionData;
78+
if (protData && protData.sessionType) {
79+
this.sessionType = protData.sessionType;
8280
}
8381
},
8482

0 commit comments

Comments
 (0)