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

Commit

Permalink
Merge branch 'release/1.14.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
bbert committed Feb 8, 2018
2 parents f1b61eb + f8cc8cd commit 685dfdf
Show file tree
Hide file tree
Showing 23 changed files with 305 additions and 262 deletions.
18 changes: 11 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ branches:
- /(release).*/
stages:
- build
- deploy
- name: test
# Run test stage only if cron job
if: type = cron
Expand All @@ -25,11 +26,7 @@ env:
- BROWSER=edge
# - BROWSER=firefox
before_install:
- openssl aes-256-cbc -K $encrypted_f186f3e7458a_key -iv $encrypted_f186f3e7458a_iv -in travis_deploy.enc -out travis_deploy -d
- npm install -g gulp
- chmod 600 travis_deploy
- eval `ssh-agent -s`
- ssh-add travis_deploy
install:
- npm install
jobs:
Expand All @@ -40,12 +37,19 @@ jobs:
- npm run build
# Build/generate the jsdoc
- npm run doc
# Package and deploy version on project's pages
- npm run deploy
- |
if [ "$TRAVIS_BRANCH" == "master" ] || [ "$TRAVIS_BRANCH" == "development" ]; then
# Package and deploy version on project's pages
openssl aes-256-cbc -K $encrypted_f186f3e7458a_key -iv $encrypted_f186f3e7458a_iv -in travis_deploy.enc -out travis_deploy -d
chmod 600 travis_deploy
eval `ssh-agent -s`
ssh-add travis_deploy
npm run deploy
fi
deploy:
api_key:
secure: fLr/s6xT5T2mh2UaPUtt3UlkdmvRkqzOlolJss3c6OICeFegFmx/ieuf8iACnB5u3fZ1pgY9/wIXq9f6uKUpTsDQd/B0uALpe/Nzv/OFGkC1S8qk66Z9VC4/LNkDSEOryAKDDPwMgcZgxyPe5u20NrVUKahMB0B4vhYKwGle5LQ=
on:
branch: master
tags: true
skip_cleanup: true
skip_cleanup: true
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ In the case of protected content, here is an example illustrating setting of the
laURL: "<licenser_url>",
withCredentials: "<license_request_withCredentials_value (true or false)>",
cdmData: "<CDM_specific_data>", // Supported by PlayReady key system (using MS-prefixed EME API) only
pssh: "<pssh (as Base64 string)>" // Considered for Widevine key system only
serverCertificate: "<license_server_certificate (as Base64 string)>"
audioRobustness: "<audio_robustness_level>" // Considered for Widevine key system only
videoRobustness: "<video_robustness_level>" // Considered for Widevine key system only
Expand Down
13 changes: 12 additions & 1 deletion RELEASES NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
### Release Notes v1.14.0 (2018/02/08)
* [MSS] Add automatic Widevine pssh generation [#216]
* [MSS] Detect PlayReady messages encoding [#207]
* Avoid seeking to stream duration [#219]
* Bugs fixing:
* - Do not remove past buffers for generic WebKit [#205]
* - Fix ArrayBuffer.isView method implementation [#206]
* - Fix initData type passing to CDM for ProtectionModel_01b [#208]
* - Perform null check on playBackQuality [#211]
* - [MSS] Fix for live stream with only one entry in tfrf box [#215]

### Release Notes v1.13.1 (2017/12/01)
* Bugs fixing:
* - Fix regression on segment download error management

### Release Notes v1.13.0 (2017/11/09)
* [MSS] Enhanced support for live start-over streams, processed as 'static' streams) [#196]
* [MSS] Enhanced support for live start-over streams, processed as 'static' streams [#196]
* [MSS] Add support for chunk 'r' (repeat) attribute [#198]
* Bugs fixing:
* - Bug fix on metrics persistence [#192]
Expand Down
2 changes: 1 addition & 1 deletion app/js/hls/HlsStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ Hls.dependencies.HlsStream = function() {
getCertificate = function () {
var protData = getKsProtectionData('com.apple.fps.1_0');
if (!protData || !protData.serverCertificate) {
return [];
return new Uint8Array(0);
}
return BASE64.decodeArray(protData.serverCertificate);
},
Expand Down
166 changes: 69 additions & 97 deletions app/js/mss/MssFragmentController.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,72 +18,76 @@ Mss.dependencies.MssFragmentController = function() {

var processTfrf = function(request, tfrf, tfdt, adaptation) {
var manifest = this.manifestModel.getValue(),
segmentsUpdated = false,
segments = adaptation.SegmentTemplate.SegmentTimeline.S_asArray,
timescale = adaptation.SegmentTemplate.timescale,
entries = tfrf.entry,
entry,
segment = null,
segmentTime,
t = 0,
i = 0,
availabilityStartTime = null,
type = adaptation.type,
range;

// Process tfrf only for live streams
// Process tfrf only for live or start-over streams
if (!this.manifestExt.getIsDynamic(manifest) && !this.manifestExt.getIsStartOver(manifest)) {
return;
}

// Go through tfrf entries
if (entries.length === 0) {
return;
}

// Consider only first tfrf entry (to avoid pre-condition failure on fragment info requests)
entry = entries[0];

// !! For tfrf fragment_absolute_time and fragment_duration are returned as goog.math.Long values (see mp4lib)
while (i < entries.length) {
// Check if time is not greater than Number.MAX_SAFE_INTEGER (2^53-1), see MssParser
// => fragment_absolute_timeManifest = original timestamp value as a string (for constructing the fragment request url, see DashHandler)
// => fragment_absolute_time = number value of timestamp (maybe rounded value, but only for 0.1 microsecond)
if (entries[i].fragment_absolute_time.greaterThan(goog.math.Long.fromNumber(Number.MAX_SAFE_INTEGER))) {
entries[i].fragment_absolute_timeManifest = entries[i].fragment_absolute_time.toString();
}

// Convert goog.math.Long to Number values
entries[i].fragment_absolute_time = entries[i].fragment_absolute_time.toNumber();
entries[i].fragment_duration = entries[i].fragment_duration.toNumber();

// In case of start-over streams, check if we have reached end of original manifest duration (set in timeShiftBufferDepth)
// => then do not update anymore timeline
if (this.manifestExt.getIsStartOver(manifest)) {
// Get first segment time
segmentTime = segments[0].tManifest ? parseFloat(segments[0].tManifest) : segments[0].t;
if (entries[i].fragment_absolute_time > (segmentTime + (manifest.timeShiftBufferDepth * timescale))) {
break;
}
}
// Check if time is not greater than Number.MAX_SAFE_INTEGER (2^53-1), see MssParser
// => fragment_absolute_timeManifest = original timestamp value as a string (for constructing the fragment request url, see DashHandler)
// => fragment_absolute_time = number value of timestamp (maybe rounded value, but only for 0.1 microsecond)
if (entry.fragment_absolute_time.greaterThan(goog.math.Long.fromNumber(Number.MAX_SAFE_INTEGER))) {
entry.fragment_absolute_timeManifest = entry.fragment_absolute_time.toString();
}

// Get last segment time
segmentTime = segments[segments.length - 1].tManifest ? parseFloat(segments[segments.length - 1].tManifest) : segments[segments.length - 1].t;
// Check if we have to append new segment to timeline
if (entries[i].fragment_absolute_time > segmentTime) {
this.debug.log("[MssFragmentController][" + type + "] Add new segment - t = " + (entries[i].fragment_absolute_time / timescale));
segment = {};
segment.t = entries[i].fragment_absolute_time;
segment.d = entries[i].fragment_duration;
// If timestamps starts at 0 relative to 1st segment (dynamic to static) then update segment time
if (segments[0].tManifest) {
segment.t -= parseFloat(segments[0].tManifest) - segments[0].t;
}
// Set tManifest either in case of timestamps greater then 2^53 or in case of dynamic to static streams
if (entries[i].fragment_absolute_timeManifest) {
segment.tManifest = entries[i].fragment_absolute_timeManifest;
} else if (segments[0].tManifest) {
segment.tManifest = entries[i].fragment_absolute_time;
}
segments.push(segment);
segmentsUpdated = true;
}
// Convert goog.math.Long to Number values
entry.fragment_absolute_time = entry.fragment_absolute_time.toNumber();
entry.fragment_duration = entry.fragment_duration.toNumber();

// In case of start-over streams, check if we have reached end of original manifest duration (set in timeShiftBufferDepth)
// => then do not update anymore timeline
if (this.manifestExt.getIsStartOver(manifest)) {
// Get first segment time
segmentTime = segments[0].tManifest ? parseFloat(segments[0].tManifest) : segments[0].t;
if (entry.fragment_absolute_time > (segmentTime + (manifest.timeShiftBufferDepth * timescale))) {
return;
}
}

// Get last segment time
segmentTime = segments[segments.length - 1].tManifest ? parseFloat(segments[segments.length - 1].tManifest) : segments[segments.length - 1].t;

i += 1;
// Check if we have to append new segment to timeline
if (entry.fragment_absolute_time <= segmentTime) {
return;
}

this.debug.log("[MssFragmentController][" + type + "] Add new segment - t = " + (entry.fragment_absolute_time / timescale));
segment = {};
segment.t = entry.fragment_absolute_time;
segment.d = entry.fragment_duration;
// If timestamps starts at 0 relative to 1st segment (dynamic to static) then update segment time
if (segments[0].tManifest) {
segment.t -= parseFloat(segments[0].tManifest) - segments[0].t;
}
// Set tManifest either in case of timestamps greater then 2^53 or in case of dynamic to static streams
if (entry.fragment_absolute_timeManifest) {
segment.tManifest = entry.fragment_absolute_timeManifest;
} else if (segments[0].tManifest) {
segment.tManifest = entry.fragment_absolute_time;
}
segments.push(segment);

// In case of static start-over streams, update content duration
if (this.manifestExt.getIsStartOver(manifest)) {
if (type === 'video') {
Expand All @@ -95,48 +99,21 @@ Mss.dependencies.MssFragmentController = function() {
}
return;
}

// Update segment timeline in case the timestamps from tfrf differ from timestamps in Manifest.
// In that case we consider tfrf timing
// var j = 0,
// segmentId = -1,
// for (j = segments.length - 1; j >= 0; j -= 1) {
// if (segments[j].t === tfdt.baseMediaDecodeTime) {
// segmentId = j;
// break;
// }
// }
// if (segmentId >= 0) {
// for (i = 0; i < entries.length; i += 1) {
// if (segmentId + i < segments.length) {
// t = segments[segmentId + i].t;
// if ((t + segments[segmentId + i].d) !== entries[i].fragment_absolute_time) {
// segments[segmentId + i].t = entries[i].fragment_absolute_time;
// segments[segmentId + i].d = entries[i].fragment_duration;
// this.debug.log("[MssFragmentController] Correct tfrf time = " + entries[i].fragment_absolute_time + " and duration = " + entries[i].fragment_duration);
// segmentsUpdated = true;
// }
// }
// }
// }

// Update segment timeline according to DVR window
if (manifest.timeShiftBufferDepth && manifest.timeShiftBufferDepth > 0) {
if (segmentsUpdated) {
// Get timestamp of the last segment
segment = segments[segments.length - 1];
t = segment.t;

// Determine the segments' availability start time
availabilityStartTime = t - (manifest.timeShiftBufferDepth * timescale);

// Remove segments prior to availability start time
// In case of live streams, update segment timeline according to DVR window
else if (manifest.timeShiftBufferDepth && manifest.timeShiftBufferDepth > 0) {
// Get timestamp of the last segment
segment = segments[segments.length - 1];
t = segment.t;

// Determine the segments' availability start time
availabilityStartTime = t - (manifest.timeShiftBufferDepth * timescale);

// Remove segments prior to availability start time
segment = segments[0];
while (segment.t < availabilityStartTime) {
this.debug.log("[MssFragmentController][" + type + "] Remove segment - t = " + (segment.t / timescale));
segments.splice(0, 1);
segment = segments[0];
while (segment.t < availabilityStartTime) {
this.debug.log("[MssFragmentController][" + type + "] Remove segment - t = " + (segment.t / timescale));
segments.splice(0, 1);
segment = segments[0];
}
}

// Update DVR window range => set range's end to end time of current segment
Expand All @@ -159,8 +136,7 @@ Mss.dependencies.MssFragmentController = function() {
traf = null,
tfdt = null,
tfrf = null,
pos,
i = 0;
pos;

// Create new fragment
fragment = mp4lib.deserialize(bytes);
Expand Down Expand Up @@ -188,9 +164,7 @@ Mss.dependencies.MssFragmentController = function() {
}
};
} else {
for (i = 0; i < tfrf.length; i += 1) {
processTfrf.call(this, request, tfrf[i], tfdt, adaptation);
}
processTfrf.call(this, request, tfrf[0], tfdt, adaptation);
}
},

Expand Down Expand Up @@ -354,8 +328,8 @@ Mss.dependencies.MssFragmentController = function() {
traf.boxes.splice(pos + 1, 0, tfdt);
}

// Process tfrf box
if (manifest.type === 'dynamic') {
// Process tfrf box
tfrf = traf.getBoxesByType("tfrf");
if (tfrf === null || tfrf.length === 0) {
throw {
Expand All @@ -366,10 +340,8 @@ Mss.dependencies.MssFragmentController = function() {
}
};
} else {
for (i = 0; i < tfrf.length; i += 1) {
processTfrf.call(this, request, tfrf[i], tfdt, adaptation);
traf.removeBoxByType("tfrf");
}
processTfrf.call(this, request, tfrf[0], tfdt, adaptation);
traf.removeBoxByType("tfrf");
}
}

Expand Down
9 changes: 4 additions & 5 deletions app/js/mss/MssFragmentInfoController.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ Mss.dependencies.MssFragmentInfoController = function() {
return Q.when(null);
},

start = function() {
start = function(delay) {
if (!_ready || _started) {
return;
}

this.debug.info("[MssFragmentInfoController][" + _type + "] START");
_started = true;
_startTime = new Date().getTime();
_startTime = new Date().getTime() + delay * 1000;

loadNextFragmentInfo.call(this);
delayLoadNextFragmentInfo.call(this, delay);
},

stop = function() {
Expand All @@ -86,8 +86,7 @@ Mss.dependencies.MssFragmentInfoController = function() {

var adaptation = _bufferController.getData(),
segments = adaptation.SegmentTemplate.SegmentTimeline.S_asArray,
// tak before last segment to avoid precondition failed (412) errors
segment = segments[segments.length - 2],
segment = segments[segments.length - 1],
representation = adaptation.Representation_asArray[0],
request;

Expand Down
Loading

0 comments on commit 685dfdf

Please sign in to comment.