Skip to content

Commit

Permalink
Merge branch 'master' into feature/audio-track-fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
tchakabam committed Jun 4, 2018
2 parents 7367415 + a7ca28d commit ad16891
Show file tree
Hide file tree
Showing 16 changed files with 490 additions and 235 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ hls.js is written in [ECMAScript6], and transpiled in ECMAScript5 using [Babel].

## Demo

[http://video-dev.github.io/hls.js/demo](http://video-dev.github.io/hls.js/demo)
### Latest Release
[https://video-dev.github.io/hls.js/demo](https://video-dev.github.io/hls.js/demo)

### Canary
[https://video-dev.github.io/hls.js/demo?canary=true](https://video-dev.github.io/hls.js/demo?canary=true)

## Getting Started

Expand Down Expand Up @@ -84,7 +88,8 @@ HTMLVideoElement control and events could be used seamlessly.
|[<img src="https://cloud.githubusercontent.com/assets/12702747/19316434/0a3601de-9067-11e6-85e2-936b1cb099a0.png" width="120">](https://www.snapstream.com/)|[<img src="https://www.streamamg.com/wp-content/themes/barebones/_assets/images/streamamg-logo.png" width="120">](https://www.streamamg.com/)|[<img src="https://streamsharkio.sa.metacdn.com/wp-content/uploads/2015/10/streamshark-dark.svg" width="120">](https://streamshark.io/)|[<img src="https://camo.githubusercontent.com/9580f10e9bfa8aa7fba52c5cb447bee0757e33da/68747470733a2f2f7777772e7461626c6f74762e636f6d2f7374617469632f696d616765732f7461626c6f5f6c6f676f2e706e67" width="120">](http://my.tablotv.com/)|
|[<img src="https://user-images.githubusercontent.com/2803310/34083705-349c8fd0-e375-11e7-92a6-5c38509f4936.png" width="120">](https://www.streamroot.io/)|[<img src="http://vignette1.wikia.nocookie.net/tedtalks/images/c/c0/TED_logo.png/revision/20150915192527" width="120">](https://www.ted.com/)|[<img src="https://www.seeklogo.net/wp-content/uploads/2014/12/twitter-logo-vector-download.jpg" width="120">](https://twitter.com/)|[<img src="https://cloud.githubusercontent.com/assets/8201317/20566816/bc33f51c-b196-11e6-9bd3-afb71a06460b.png" width="120">](http://vwflow.com)|
|[<img src="http://media.mtvnservices.com/edge/hosted/Viacom_logo.svg" width="120">](https://www.viacom.com/)|[<img src="https://user-images.githubusercontent.com/1181974/29248959-efabc440-802d-11e7-8050-7c1f4ca6c607.png" width="120">](https://vk.com/)|[<img src="https://s3.amazonaws.com/uploads.hipchat.com/87223/4876411/7Rybnl26ReFzlt3/jw-logo-red.png" width="120">](https://www.jwplayer.com)|[<img src="https://staticftv-a.akamaihd.net/arches/francetv/default/img/og-image.jpg?20161007" width="120">](https://www.france.tv)|
|[<img src="http://showmax.akamaized.net/e/logo/showmax_black.png" width="120">](https://tech.showmax.com)|[<img src="https://static3.1tv.ru/assets/web/logo-8ff7c63246d8df0397233927db52edbb.svg" width="120" height="120">](https://www.1tv.ru/) | | |
|[<img src="http://showmax.akamaized.net/e/logo/showmax_black.png" width="120">](https://tech.showmax.com)|[<img src="https://static3.1tv.ru/assets/web/logo-8ff7c63246d8df0397233927db52edbb.svg" width="120" height="120">](https://www.1tv.ru/) | [<img src="https://user-images.githubusercontent.com/1480052/40482633-c013ebce-5f55-11e8-96d5-b776415de0ce.png" width="120">](https://www.zdf.de) | |




Expand All @@ -100,6 +105,7 @@ hls.js is (being) integrated in the following players:
- [Videojs](http://videojs.com) through [Videojs-hlsjs](https://github.com/benjipott/videojs-hlsjs)
- [Videojs](http://videojs.com) through [videojs-hls.js](https://github.com/streamroot/videojs-hls.js). hls.js is integrated as a SourceHandler -- new feature in Video.js 5.
- [Videojs](http://videojs.com) through [videojs-contrib-hls.js](https://github.com/Peer5/videojs-contrib-hls.js). Production ready plug-in with full fallback compatibility built-in.
- [Fluid Player](https://www.fluidplayer.com)


## Chrome/Firefox integration
Expand Down
32 changes: 25 additions & 7 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@

<link rel="stylesheet" href="style.css">

<link rel="preload" href="../dist/hls-demo.js" as="script">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>

</head>

<body>
Expand Down Expand Up @@ -135,7 +136,7 @@ <h3>

<label class="center">Error:</label>
<pre id="errorOut" class="center" style="white-space: pre-wrap;"></pre>

<div class="center" style="text-align: center;" id="toggleButtons">
<button type="button" class="btn btn-sm" onclick="toggleTab('playbackControlTab');">Playback</button>
<button type="button" class="btn btn-sm" onclick="toggleTab('qualityLevelControlTab');">Quality-levels</button>
Expand Down Expand Up @@ -289,10 +290,27 @@ <h4>Buffer &amp; Statistics</h4>
<script src="metrics.js"></script>
<script src="jsonpack.js"></script>

<!-- Compiled lib dist -->
<script src="../dist/hls.js"></script>
<!-- Compiled demo main -->
<script src="../dist/hls-demo.js"></script>

<script>
(function() {
function loadScript(url, onLoad) {
var s = document.createElement("script");
s.setAttribute('src', url);
if (onLoad) {
s.onload = onLoad;
}
document.body.appendChild(s);
}

// load compiled lib dist, or latest canary from jsdelivr (?canary=true)
var src = window.location.search.substring(1).split('&').indexOf('canary=true') >= 0
? 'https://cdn.jsdelivr.net/npm/hls.js@canary'
: '../dist/hls.js';

loadScript(src, function() {
// load compiled demo main
loadScript('../dist/hls-demo.js');
});
})();
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ When set, use this level as the default hls.startLevel. Keep in mind that the st

### `fragLoadingTimeOut` / `manifestLoadingTimeOut` / `levelLoadingTimeOut`

(default: 60000ms for fragment / 10000ms for level and manifest)
(default: 20000ms for fragment / 10000ms for level and manifest)

URL Loader timeout.
A timeout callback will be triggered if loading duration exceeds this timeout.
Expand Down
2 changes: 2 additions & 0 deletions scripts/travis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ elif [ "${TRAVIS_MODE}" = "releaseCanary" ]; then
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> .npmrc
npm publish --tag canary
echo "Published canary."
curl https://purge.jsdelivr.net/npm/hls.js@canary
echo "Cleared jsdelivr cache."
else
echo "Canary already published."
fi
Expand Down
2 changes: 2 additions & 0 deletions src/controller/audio-stream-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ class AudioStreamController extends TaskLoop {

onHandlerDestroying () {
this.stopLoad();
super.onHandlerDestroying();
}

onHandlerDestroyed () {
this.state = State.STOPPED;
this.fragmentTracker = null;
super.onHandlerDestroyed();
}

// Signal that video PTS was found
Expand Down
115 changes: 115 additions & 0 deletions src/controller/fragment-finders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import BinarySearch from '../utils/binary-search';

/**
* Calculates the PDT of the next load position.
* bufferEnd in this function is usually the position of the playhead.
* @param {number} [start = 0] - The PTS of the first fragment within the level
* @param {number} [bufferEnd = 0] - The end of the contiguous buffered range the playhead is currently within
* @param {*} levelDetails - An object containing the parsed and computed properties of the currently playing level
* @returns {number} nextPdt - The computed PDT
*/
export function calculateNextPDT (start = 0, bufferEnd = 0, levelDetails) {
let pdt = 0;
if (levelDetails.programDateTime) {
const parsedDateInt = Date.parse(levelDetails.programDateTime);
if (!isNaN(parsedDateInt)) {
pdt = (bufferEnd * 1000) + parsedDateInt - (1000 * start);
}
}
return pdt;
}

/**
* Finds the first fragment whose endPDT value exceeds the given PDT.
* @param {Array<Fragment>} fragments - The array of candidate fragments
* @param {number|null} [PDTValue = null] - The PDT value which must be exceeded
* @returns {*|null} fragment - The best matching fragment
*/
export function findFragmentByPDT (fragments, PDTValue = null) {
if (!Array.isArray(fragments) || !fragments.length || PDTValue === null) {
return null;
}

// if less than start
let firstSegment = fragments[0];

if (PDTValue < firstSegment.pdt) {
return null;
}

let lastSegment = fragments[fragments.length - 1];

if (PDTValue >= lastSegment.endPdt) {
return null;
}

for (let seg = 0; seg < fragments.length; ++seg) {
let frag = fragments[seg];
if (PDTValue < frag.endPdt) {
return frag;
}
}
return null;
}

/**
* Finds a fragment based on the SN of the previous fragment; or based on the needs of the current buffer.
* This method compensates for small buffer gaps by applying a tolerance to the start of any candidate fragment, thus
* breaking any traps which would cause the same fragment to be continuously selected within a small range.
* @param {*} fragPrevious - The last frag successfully appended
* @param {Array<Fragment>} fragments - The array of candidate fragments
* @param {number} [bufferEnd = 0] - The end of the contiguous buffered range the playhead is currently within
* @param {number} [end = 0] - The computed end time of the stream
* @param {number} maxFragLookUpTolerance - The amount of time that a fragment's start can be within in order to be considered contiguous
* @returns {*} foundFrag - The best matching fragment
*/
export function findFragmentBySN (fragPrevious, fragments, bufferEnd = 0, end = 0, maxFragLookUpTolerance = 0) {
let foundFrag;
const fragNext = fragPrevious ? fragments[fragPrevious.sn - fragments[0].sn + 1] : null;
if (bufferEnd < end) {
if (bufferEnd > end - maxFragLookUpTolerance) {
maxFragLookUpTolerance = 0;
}

// Prefer the next fragment if it's within tolerance
if (fragNext && !fragmentWithinToleranceTest(bufferEnd, maxFragLookUpTolerance, fragNext)) {
foundFrag = fragNext;
} else {
foundFrag = BinarySearch.search(fragments, fragmentWithinToleranceTest.bind(null, bufferEnd, maxFragLookUpTolerance));
}
}
return foundFrag;
}

/**
* The test function used by the findFragmentBySn's BinarySearch to look for the best match to the current buffer conditions.
* @param {*} candidate - The fragment to test
* @param {number} [bufferEnd = 0] - The end of the current buffered range the playhead is currently within
* @param {number} [maxFragLookUpTolerance = 0] - The amount of time that a fragment's start can be within in order to be considered contiguous
* @returns {number} - 0 if it matches, 1 if too low, -1 if too high
*/
export function fragmentWithinToleranceTest (bufferEnd = 0, maxFragLookUpTolerance = 0, candidate) {
// offset should be within fragment boundary - config.maxFragLookUpTolerance
// this is to cope with situations like
// bufferEnd = 9.991
// frag[Ø] : [0,10]
// frag[1] : [10,20]
// bufferEnd is within frag[0] range ... although what we are expecting is to return frag[1] here
// frag start frag start+duration
// |-----------------------------|
// <---> <--->
// ...--------><-----------------------------><---------....
// previous frag matching fragment next frag
// return -1 return 0 return 1
// logger.log(`level/sn/start/end/bufEnd:${level}/${candidate.sn}/${candidate.start}/${(candidate.start+candidate.duration)}/${bufferEnd}`);
// Set the lookup tolerance to be small enough to detect the current segment - ensures we don't skip over very small segments
let candidateLookupTolerance = Math.min(maxFragLookUpTolerance, candidate.duration + (candidate.deltaPTS ? candidate.deltaPTS : 0));
if (candidate.start + candidate.duration - candidateLookupTolerance <= bufferEnd) {
return 1;
} else if (candidate.start - candidateLookupTolerance > bufferEnd && candidate.start) {
// if maxFragLookUpTolerance will have negative value then don't return -1 for first element
return -1;
}

return 0;
}
2 changes: 1 addition & 1 deletion src/controller/fragment-tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export class FragmentTracker extends EventHandler {
}

getFragmentKey (fragment) {
return `${fragment.type}_${fragment.level}_${fragment.sn}`;
return `${fragment.type}_${fragment.level}_${fragment.urlId}_${fragment.sn}`;
}

/**
Expand Down
Loading

0 comments on commit ad16891

Please sign in to comment.