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

Commit 423c96d

Browse files
committed
Merge branch 'release/1.10.0'
2 parents ee84f4e + 28fa2d8 commit 423c96d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2472
-1587
lines changed

.npmignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
samples
2+
docs
3+
build
4+
test
5+
.travis.yml
6+
reports
7+
8+
.idea

.travis.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
language: node_js
2+
branches:
3+
only:
4+
- master
5+
- development
6+
- /(release).*/
27
env:
38
global:
49
- ENCRYPTION_LABEL: 98a7d362e1e4
10+
matrix:
11+
- BUILD=true TEST=false
12+
- BUILD=false TEST=true BROWSER=chrome
13+
- BUILD=false TEST=true BROWSER=ie
14+
- BUILD=false TEST=true BROWSER=edge
15+
- BUILD=false TEST=true BROWSER=firefox
516
node_js:
617
- stable
718
addons:
819
browserstack:
920
username: "bertrandberthelo1"
1021
access_key:
11-
secure: "ZPgCkVlmzP1pSgC9UF5WhZioV//c8QG6LlMqhWa96LjPlybNX12QY/mfzY9QvEC4qYCkeHKg/OKPm2pNF/7QuW76Zf6hJ80W3pLH+lGCuNQ+uywk5QvV95nYLWp+fIes5DKqdnGPhF4Ft/Ggkq4NlGAwpRID2P7Sxz1V4ARF/qY="
22+
secure: "kB8iXiydT+xheyHox2zwq/1k75uUmF+F2b9k76Nhbb001Mh5608kzhH9xXFM+BUyM1pm3LImF+vYcSfKMYlDn/KBB7s9p8TJfwC/obbmtWJucSjtRiVo9aOOa7Ox2M+ACb0rsLpvzFRiHtYo0HZNFVkIfvqZN389Imm6UCOXsyo="
1223
before_install:
1324
- openssl aes-256-cbc -K $encrypted_98a7d362e1e4_key -iv $encrypted_98a7d362e1e4_iv -in travis_deploy.enc -out travis_deploy -d
1425
- npm install -g gulp
@@ -18,7 +29,7 @@ before_install:
1829
install:
1930
- npm install
2031
script:
21-
- npm run build
22-
- npm run deploy
23-
#after_success:
24-
# - npm test
32+
- if [[ "$BUILD" = "true" ]]; then npm run build ; fi
33+
- if [[ "$BUILD" = "true" ]]; then npm run deploy ; fi
34+
- if [[ "$BUILD" = "true" ]]; then npm run dist ; fi
35+
- if [[ "$TEST" = "true" && "$TRAVIS_BRANCH" != "master" && "$TRAVIS_BRANCH" != "development" ]]; then npm test ; fi

README.md

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ hasplayer.js is an extension of the [dash.js](https://github.com/Dash-Industry-F
66

77
If your intent is to use the player code without contributing back to this project, then use the MASTER branch which holds the approved and stable public releases.
88

9-
If your goal is to improve or extend the code and contribute back to this project, then you should make your changes in, and submit a pull request against, the DEVELOPMENT branch.
9+
If your goal is to improve or extend the code and contribute back to this project, then you should make your changes in, and submit a pull request against, the DEVELOPMENT branch.
1010

1111
Learn more about versions and roadmap on the [wiki](https://github.com/Orange-OpenSource/hasplayer.js/wiki).
1212

@@ -22,7 +22,10 @@ Learn more about versions and roadmap on the [wiki](https://github.com/Orange-Op
2222

2323
1. [install nodejs](http://nodejs.org/)
2424
2. [install gulp](https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md)
25-
* npm install -g gulp
25+
26+
```
27+
npm install -g gulp
28+
```
2629

2730
### Build / Run
2831

@@ -32,9 +35,13 @@ The build task can be configured in order to select supported protocol(s) and to
3235
For example:
3336

3437
1. No hls support, no EME support:
35-
* npm run build -- --no-hls --no-protection
38+
```
39+
npm run build -- --no-hls --no-protection
40+
```
3641
2. No hls support, no MSS support:
37-
* npm run build -- --no-hls --no-mss
42+
```
43+
npm run build -- --no-hls --no-mss
44+
```
3845

3946
## Demo
4047

@@ -51,20 +58,20 @@ See LICENSE file for copyright details.
5158
## Getting Started
5259

5360
Create a video element somewhere in your html. For our purposes, make sure to set the controls property to true.
54-
```
61+
```html
5562
<video id="videoPlayer" controls="true"></video>
5663
```
5764

5865
Add hasplayer.js to the end of the body.
59-
```
66+
```html
6067
<body>
6168
...
6269
<script src="yourPathToHasplayer/hasplayer.js"></script>
6370
</body>
6471
```
6572

6673
Now comes the good stuff. We need to create an MediaPlayer. Then we need to initialize it, attach it to our "videoPlayer" and then tell it where to get the video from. We will do this in an anonymous self executing function, that way it will run as soon as the page loads. So, here is how we do it:
67-
``` js
74+
```js
6875
(function(){
6976
var stream = {
7077
url: "http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest"
@@ -76,7 +83,7 @@ Now comes the good stuff. We need to create an MediaPlayer. Then we need to init
7683
```
7784

7885
When it is all done, it should look similar to this:
79-
```
86+
```html
8087
<!doctype html>
8188
<html>
8289
<head>
@@ -100,15 +107,80 @@ When it is all done, it should look similar to this:
100107
</body>
101108
</html>
102109
```
110+
## DRM Video Stream
111+
In the case of protected content, here is an example illustrating setting of the protection data:
112+
```html
113+
<!doctype html>
114+
<html>
115+
<head>
116+
<title>Hasplayer.js Rocks</title>
117+
</head>
118+
<body>
119+
<div>
120+
<video id="videoPlayer" controls="true"></video>
121+
</div>
122+
<script src="yourPathToHasplayer/hasplayer.js"></script>
123+
<script>
124+
(function(){
125+
var stream = {
126+
url: "<manifest_url>",
127+
protData: {
128+
com.microsoft.playready: {
129+
laURL: "<licenser_url>",
130+
cdmData: "<specific_CDM_data>"
131+
}
132+
}
133+
};
134+
var mediaPlayer = new MediaPlayer();
135+
mediaPlayer.init(document.querySelector("#videoPlayer"));
136+
mediaPlayer.load(stream);
137+
})();
138+
</script>
139+
</body>
140+
</html>
141+
```
142+
143+
## Events
144+
145+
MediaPlayer offers events to be notified of differents events on video streaming. Those events are, for a part, sent by the HTMLMediaElement (&lt;video&gt;), and for an other part, sent by the MediaPlayer.
146+
147+
```js
148+
function registerMediaPlayerEvents() {
149+
// MediaPlayer events
150+
mediaPlayer.addEventListener("error", onError);
151+
mediaPlayer.addEventListener("warning", onWarning);
152+
mediaPlayer.addEventListener("cueEnter", onCueEnter);
153+
mediaPlayer.addEventListener("cueExit", onCueExit);
154+
mediaPlayer.addEventListener("play_bitrate", onPlayBitrateChanged);
155+
mediaPlayer.addEventListener("download_bitrate", onDownloadBitrateChanged);
156+
mediaPlayer.addEventListener("manifestUrlUpdate", onManifestUrlUpdate);
157+
mediaPlayer.addEventListener("metricAdded", onMetricAdded);
158+
mediaPlayer.addEventListener("metricChanged", onMetricChanged);
159+
mediaPlayer.addEventListener("bufferLevel_updated", onBufferLevelUpdated);
160+
mediaPlayer.addEventListener("state_changed", onStateChanged);
161+
// <video> element events
162+
mediaPlayer.addEventListener("loadeddata", onload);
163+
mediaPlayer.addEventListener("play", onPlay);
164+
mediaPlayer.addEventListener("pause", onPause);
165+
mediaPlayer.addEventListener("timeupdate", onTimeUpdate);
166+
mediaPlayer.addEventListener("volumechange", onVolumeChange);
167+
};
168+
```
169+
For instance, callback function looks like this :
170+
```js
171+
function onPlayBitrateChanged(e) {
172+
handlePlayBitrate(e.detail.bitrate, e.detail.time);
173+
};
174+
```
103175

104176
## Documentation
105177

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

108180
This API documentation can be generated using following gulp command:
109-
181+
```
110182
npm run doc
111-
183+
```
112184

113185
### Tested With
114186

RELEASES NOTES.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
### Release Notes v1.10.0 (2017/04/13)
2+
* Adapt EME's protection model 21Jan2015 to chrome 58 updates (secure origins and server certificate)
3+
* - Check requestMediaKeySystemAccess API availability when requesting key system access
4+
* - Add possibility to provide server certificate when loading a stream
5+
* Filter unsupported video and audio qualities (codecs) to avoid switching to a unsupported quality while playing
6+
* Remove outdated buffer according to 'BufferController.bufferToKeep' configuration parameter value (this avoids QuotaExceededError on Firefox)
7+
* Bugs fixing:
8+
* - [HLS] Fix H.264 bytestream to MP4 conversion (i.e. support 3 or 4 bytes start codes)
9+
* - [HLS] Fix segment alignment when switching alternative track
10+
* - Consolidate automatic live session reloading after multiple segment download failures
11+
112
### Release Notes v1.9.0 (2017/03/08)
213
* Consolidate EME/Protection layer management:
314
* - Start playback only once ProtectionController is initialized (avoids conflicts on Chrome when setting MediaKeys on <video>)

app/js/dash/DashManifestExtensions.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Dash.dependencies.DashManifestExtensions.prototype = {
3535
if (adaptation.type === undefined) {
3636
adaptation.type = null;
3737
}
38-
38+
3939
col = adaptation.ContentComponent_asArray;
4040

4141
if (col) {
@@ -251,7 +251,7 @@ Dash.dependencies.DashManifestExtensions.prototype = {
251251
datas = [],
252252
i;
253253

254-
//return datas;
254+
// return datas;
255255

256256
if (!manifest || periodIndex < 0) {
257257
return datas;
@@ -262,7 +262,7 @@ Dash.dependencies.DashManifestExtensions.prototype = {
262262
if (adaptations.length === 0) {
263263
return datas;
264264
}
265-
265+
266266
for (i = 0; i < adaptations.length; i += 1) {
267267
if (this.getIsAudio(adaptations[i])) {
268268
datas.push(adaptations[i]);
@@ -328,15 +328,21 @@ Dash.dependencies.DashManifestExtensions.prototype = {
328328

329329
while ((codec === null) && (i < adaptation.Representation_asArray.length)) {
330330
representation = adaptation.Representation_asArray[i];
331-
if (representation.codecs !== null && representation.codecs !== "") {
332-
codec = (representation.mimeType + ';codecs="' + representation.codecs + '"');
333-
}
331+
codec = this.getCodecForRepresentation(representation);
334332
i++;
335333
}
336334

337335
return codec;
338336
},
339337

338+
getCodecForRepresentation: function(representation) {
339+
"use strict";
340+
if (representation.codecs === null || representation.codecs === "") {
341+
return null;
342+
}
343+
return (representation.mimeType + ';codecs="' + representation.codecs + '"');
344+
},
345+
340346
getMimeType: function(data) {
341347
"use strict";
342348
return data.Representation_asArray[0].mimeType;

app/js/hls/HlsDemux.js

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Hls.dependencies.HlsDemux = function() {
2323
return tmp;
2424
};
2525

26+
// List of considered H.264 NALU types
27+
var H264_NALU_TYPES = [1, 5, 6];
28+
2629
var trackIdCounter = 1,
2730
pidToTrack = [],
2831
tracks = [],
@@ -227,7 +230,7 @@ Hls.dependencies.HlsDemux = function() {
227230

228231
// In case of H.264 stream, convert bytestream to MP4 format (NALU size field instead of start codes)
229232
if (track.streamType.search('H.264') !== -1) {
230-
mpegts.h264.bytestreamToMp4(track.data);
233+
convertH264Frames.call(this, track);
231234
}
232235

233236
// In case of AAC-ADTS stream, demultiplex ADTS frames into AAC frames
@@ -251,6 +254,60 @@ Hls.dependencies.HlsDemux = function() {
251254

252255
},
253256

257+
convertH264Frames = function(track) {
258+
var sample,
259+
nalu,
260+
totalLength,
261+
data,
262+
offset,
263+
i, n;
264+
265+
// Parse all NALUs and determine total data length according to filtered NALUs
266+
totalLength = 0;
267+
offset = 0;
268+
for (i = 0; i < track.samples.length; i++) {
269+
sample = track.samples[i];
270+
sample.nalus = mpegts.h264.parseNALUs(track.data.subarray(offset, offset + sample.size));
271+
for (n = 0; n < sample.nalus.length; n++) {
272+
nalu = sample.nalus[n];
273+
// this.debug.log("[HlsDemux][" + track.type + "] H264 NALU, type = " + nalu.type + ", size = " + nalu.size + " - write: " + (H264_NALU_TYPES.indexOf(nalu.type) !== -1));
274+
if (H264_NALU_TYPES.indexOf(nalu.type) !== -1) {
275+
// Set NALU offset relative to whole data array
276+
nalu.offset += offset;
277+
totalLength += 4 + sample.nalus[n].size; // 4 = NALUSize field length
278+
} else {
279+
// Remove NALU
280+
sample.nalus.splice(n, 1);
281+
n--;
282+
}
283+
}
284+
offset += sample.size;
285+
}
286+
287+
// Allocate new data
288+
data = new Uint8Array(totalLength);
289+
290+
// Copy all NALUs from each sample (AU) into output data
291+
offset = 0;
292+
for (i = 0; i < track.samples.length; i++) {
293+
sample = track.samples[i];
294+
sample.size = 0;
295+
for (n = 0; n < sample.nalus.length; n++) {
296+
nalu = sample.nalus[n];
297+
data[offset++] = (nalu.size & 0xFF000000) >> 24;
298+
data[offset++] = (nalu.size & 0x00FF0000) >> 16;
299+
data[offset++] = (nalu.size & 0x0000FF00) >> 8;
300+
data[offset++] = (nalu.size & 0x000000FF);
301+
data.set(track.data.subarray(nalu.offset, nalu.offset + nalu.size), offset);
302+
offset += nalu.size;
303+
sample.size += 4 + nalu.size;
304+
}
305+
}
306+
307+
// Replace track data with converted H.264 frames
308+
track.data = data;
309+
},
310+
254311
demuxADTS = function(track) {
255312
var aacFrames,
256313
aacSamples = [],

app/js/hls/HlsFragmentController.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ Hls.dependencies.HlsFragmentController = function () {
3232
mpegts: tracks[i].samples[0].mpegTimestamp
3333
};
3434
}
35-
36-
if (tracks[i].type === "video") {
37-
request.startTime = tracks[i].samples[0].dts / tracks[i].timescale;
38-
}
3935
}
4036

4137
// Generate init (moov) and media segment (moof)

app/js/hls/HlsParser.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,11 @@ Hls.dependencies.HlsParser = function() {
340340
var segments = adaptation.Representation_asArray[j].SegmentList.SegmentURL_asArray;
341341
if (segments[0].sequenceNumber < maxSequenceNumber) {
342342
removeSegments(segments, maxSequenceNumber);
343-
segments[0].time = 0;
344-
for (k = 1; k < segments.length; k++) {
345-
segments[k].time = segments[k - 1].time + segments[k - 1].duration;
343+
if (segments.length > 0) {
344+
segments[0].time = 0;
345+
for (k = 1; k < segments.length; k++) {
346+
segments[k].time = segments[k - 1].time + segments[k - 1].duration;
347+
}
346348
}
347349
}
348350
}

app/js/mss/MssParser.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ Mss.dependencies.MssParser = function() {
131131
mapRepresentation = function(qualityLevel, streamIndex) {
132132

133133
var representation = {},
134-
fourCCValue = null;
134+
fourCCValue = null,
135+
type = this.domParser.getAttributeValue(streamIndex, "Type");
135136

136137
representation.id = qualityLevel.Id;
137138
representation.bandwidth = parseInt(this.domParser.getAttributeValue(qualityLevel, "Bitrate"), 10);
@@ -149,10 +150,10 @@ Mss.dependencies.MssParser = function() {
149150
// If still not defined (optionnal for audio stream, see https://msdn.microsoft.com/en-us/library/ff728116%28v=vs.95%29.aspx),
150151
// then we consider the stream is an audio AAC stream
151152
if (fourCCValue === null || fourCCValue === "") {
152-
if (this.domParser.getAttributeValue(streamIndex, "Type") === 'audio') {
153+
if (type === 'audio') {
153154
fourCCValue = "AAC";
154155
} else {
155-
this.errHandler.sendWarning(MediaPlayer.dependencies.ErrorHandler.prototype.MEDIA_ERR_CODEC_UNSUPPORTED, "Codec/FourCC not provided", {codec: ''});
156+
this.errHandler.sendWarning(MediaPlayer.dependencies.ErrorHandler.prototype.MEDIA_ERR_CODEC_UNSUPPORTED, type + " codec/FourCC not provided", {codec: ''});
156157
return null;
157158
}
158159
}

0 commit comments

Comments
 (0)