-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Learn2Adapt Low Latency bitrate adaptation algo * Definition of L2ARule in ABRRules * Update with abrL2A strategy * comments * Updated MPD url * L2A implementation * Remove duplicate constant * Set BOLA to false when using L2A. Fix linting errors * Remove unused settings parameter useBufferOccupancyABR * Add L2A to default ABR rules * Small refactor in RulesContext.js * Add L2ALL sample page * Add L2ALL to reference client * Remove createAbrRulesCollection call from MediaPlayer.js * Adjust logic in ABRRulesCollection.js * Add mediaType sepcific handling to L2ARule.js and refactor some parts Co-authored-by: thalka <theodore.karagkioules@gmail.com>
- Loading branch information
Showing
14 changed files
with
970 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,286 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"/> | ||
<title>Low latency live stream instantiation example with local execution</title> | ||
<script src="../../dist/dash.all.debug.js"></script> | ||
<script src="../../dist/dash.all.debug.js"></script> | ||
<script src="http://code.jquery.com/jquery-3.4.1.min.js"></script> | ||
|
||
|
||
<script class="code"> | ||
var player, targetLatency, minDrift, catchupPlaybackRate, liveCatchupLatencyThreshold; | ||
|
||
function init() { | ||
var video, | ||
url = 'https://livesim.dashif.org/livesim/chunkdur_1/ato_7/testpic4_8s/Manifest300.mpd'; | ||
|
||
video = document.querySelector("video"); | ||
player = dashjs.MediaPlayer().create(); | ||
player.initialize(video, url, true); | ||
player.updateSettings({'streaming': {'lowLatencyEnabled': true}}); | ||
player.updateSettings({'debug': {'logLevel': dashjs.Debug.LOG_LEVEL_WARNING}}); | ||
|
||
player.updateSettings({ | ||
'streaming': { | ||
'abr': { | ||
'useDefaultABRRules': true, | ||
'ABRStrategy': 'abrL2A' | ||
} | ||
} | ||
}); | ||
applyParameters(); | ||
|
||
return player; | ||
} | ||
|
||
function applyParameters() { | ||
targetLatency = parseFloat(document.getElementById("target-latency").value, 10); | ||
minDrift = parseFloat(document.getElementById("min-drift").value, 10); | ||
catchupPlaybackRate = parseFloat(document.getElementById("catchup-playback-rate").value, 10); | ||
liveCatchupLatencyThreshold = parseFloat(document.getElementById("catchup-threshold").value, 10); | ||
|
||
player.updateSettings({ | ||
'streaming': { | ||
'liveDelay': targetLatency, | ||
'liveCatchUpMinDrift': minDrift, | ||
'liveCatchUpPlaybackRate': catchupPlaybackRate, | ||
'liveCatchupLatencyThreshold': liveCatchupLatencyThreshold, | ||
} | ||
}); | ||
} | ||
</script> | ||
|
||
<style> | ||
.video-wrapper { | ||
display: flex; | ||
flex-flow: row wrap; | ||
} | ||
|
||
.video-wrapper > div:nth-child(2) { | ||
margin-left: 25px; | ||
} | ||
|
||
video { | ||
width: 640px; | ||
height: 360px; | ||
} | ||
|
||
ul { | ||
margin: 0; | ||
} | ||
|
||
input { | ||
width: 5em; | ||
border: 1px solid gray; | ||
padding: 0 4px 0 8px; | ||
} | ||
|
||
.help-container { | ||
display: flex; | ||
flex-flow: row wrap; | ||
margin-top: 1em; | ||
align-content: center; | ||
background: white; | ||
border: solid 1px #ddd; | ||
padding: 0.5em; | ||
} | ||
|
||
.help-container > div { | ||
width: 33.3%; | ||
padding: 1em; | ||
box-sizing: border-box; | ||
} | ||
|
||
.help-container h3 { | ||
margin-top: 0; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div> | ||
<div class="video-wrapper"> | ||
<video controls="true" autoplay muted></video> | ||
<div> | ||
<div> | ||
<form action="javascript:applyParameters()"> | ||
<fieldset> | ||
<legend>Configurable parameters</legend> | ||
<p>Target Latency (secs): <input type="number" id="target-latency" value="2" min="0" step="0.1"> | ||
</p> | ||
<p>Min. drift (secs): <input type="number" id="min-drift" value="0.3" min="0.0" max="0.5" | ||
step="0.01"></p> | ||
<p>Catch-up playback rate (%): <input type="number" id="catchup-playback-rate" value="0.3" | ||
min="0.0" max="0.5" step="0.01"></p> | ||
<p>Live catchup latency threshold (secs): <input type="number" id="catchup-threshold" value="30"> | ||
</p> | ||
<button type="submit">Apply</button> | ||
</fieldset> | ||
</form> | ||
</div> | ||
<br> | ||
<fieldset> | ||
<legend>Current values</legend> | ||
<ul> | ||
<li>Latency: <span id="latency-tag"></span></li> | ||
<li>Min. drift: <span id="mindrift-tag"></span></li> | ||
<li>Playback rate: <span id="playbackrate-tag"></span></li> | ||
<li>Live catchup latency threshold : <span id="catchup-threshold-tag"></span></li> | ||
<li>Buffer: <b><span id="buffer-tag"></span></b></li> | ||
<li>Quality: <b><span id="quality-tag"></span></b></li> | ||
</ul> | ||
<div id="stats"></div> | ||
</fieldset> | ||
</div> | ||
</div> | ||
|
||
<p style="font-family:Arial,sans-serif; font-weight: bold; font-size: 1.1em">Concepts definition</p> | ||
<div class="help-container"> | ||
<div id="latency-help"> | ||
<h3>Latency</h3> | ||
<p>Lowering this value will lower latency but may decrease the player's ability to build a stable | ||
buffer.</p> | ||
<p><a href="http://cdn.dashjs.org/latest/jsdoc/module-MediaPlayer.html#setLiveDelay__anchor" | ||
target="_blank">setLiveDelay() doc</a></p> | ||
</div> | ||
|
||
<div id="min-drift-help"> | ||
<h3>Min. drift</h3> | ||
<p>Minimum latency deviation allowed before activating catch-up mechanism.</p> | ||
<p><a href="http://cdn.dashjs.org/latest/jsdoc/module-MediaPlayer.html#setLowLatencyMinDrift__anchor" | ||
target="_blank">setLowLatencyMinDrift() doc</a></p> | ||
</div> | ||
|
||
<div id="catch-up-playback-rate-help"> | ||
<h3>Catch-up playback rate</h3> | ||
<p>Maximum catch-up rate, as a percentage, for low latency live streams.</p> | ||
<p><a href="http://cdn.dashjs.org/latest/jsdoc/module-MediaPlayer.html#setCatchUpPlaybackRate__anchor" | ||
target="_blank">setCatchUpPlaybackRate() doc</a></p> | ||
</div> | ||
</div> | ||
</div> | ||
<script> | ||
document.addEventListener("DOMContentLoaded", function () { | ||
const player = init(); | ||
const video = document.querySelector("video") | ||
let stallingAt = null; | ||
const CMA = () => { | ||
let average = 0; | ||
let count = 0; | ||
|
||
return { | ||
average(val) { | ||
if (isNaN(val)) { | ||
return 0; | ||
} | ||
average = average + ((val - average) / ++count); | ||
return average; | ||
}, | ||
} | ||
} | ||
|
||
setInterval(function () { | ||
var dashMetrics = player.getDashMetrics(); | ||
var settings = player.getSettings(); | ||
|
||
var currentLatency = parseFloat(player.getCurrentLiveLatency(), 10); | ||
document.getElementById("latency-tag").innerHTML = currentLatency + " secs"; | ||
|
||
document.getElementById("mindrift-tag").innerHTML = settings.streaming.liveCatchUpMinDrift + " secs"; | ||
|
||
var currentPlaybackRate = player.getPlaybackRate(); | ||
document.getElementById("playbackrate-tag").innerHTML = Math.round(currentPlaybackRate * 100) / 100; | ||
|
||
var currentBuffer = dashMetrics.getCurrentBufferLevel("video"); | ||
document.getElementById("buffer-tag").innerHTML = currentBuffer + " secs"; | ||
|
||
document.getElementById("catchup-threshold-tag").innerHTML = settings.streaming.liveCatchupLatencyThreshold + " secs"; | ||
}, 200); | ||
|
||
player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_REQUESTED, (e) => { | ||
console.warn('Quality changed requested', e); | ||
}); | ||
|
||
player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, (e) => { | ||
console.warn('Quality changed', e); | ||
const quality = player.getBitrateInfoListFor('video')[e.newQuality]; | ||
if (!quality) { | ||
return; | ||
} | ||
document.querySelector('#quality-tag').innerText = `${quality.width}x${quality.height}, ${quality.bitrate / 1000}Kbps`; | ||
}); | ||
|
||
window.startRecording = () => { | ||
console.info('Begin recording'); | ||
|
||
const latencyCMA = CMA(); | ||
const bufferCMA = CMA(); | ||
const history = window.abrHistory = { | ||
switchHistory: [], | ||
stallDuration: 0, | ||
averageLatency: 0, | ||
averageBufferLength: 0, | ||
}; | ||
|
||
// Record the initial quality | ||
recordSwitch(player.getBitrateInfoListFor('video')[player.getQualityFor('video')]); | ||
|
||
let pollInterval = -1; | ||
window.stopRecording = () => { | ||
clearInterval(pollInterval); | ||
checkStallResolution(); | ||
const lastQuality = history.switchHistory[history.switchHistory.length - 1]; | ||
if (lastQuality.end === null) { | ||
lastQuality.end = video.currentTime; | ||
} | ||
console.warn('Run ended. Please navigate back to node for results.'); | ||
} | ||
|
||
pollInterval = setInterval(function () { | ||
const currentLatency = parseFloat(player.getCurrentLiveLatency(), 10); | ||
const currentBuffer = player.getDashMetrics().getCurrentBufferLevel("video"); | ||
history.averageLatency = latencyCMA.average(currentLatency); | ||
history.averageBufferLength = bufferCMA.average(currentBuffer); | ||
console.log(history); | ||
}, 200); | ||
|
||
|
||
player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, (e) => { | ||
recordSwitch(player.getBitrateInfoListFor('video')[e.newQuality]); | ||
}); | ||
|
||
video.addEventListener('waiting', (e) => { | ||
stallingAt = performance.now(); | ||
}); | ||
|
||
video.addEventListener('timeupdate', () => { | ||
checkStallResolution(); | ||
}); | ||
|
||
function recordSwitch(quality) { | ||
if (!quality) { | ||
return; | ||
} | ||
const switchHistory = history.switchHistory; | ||
const prev = switchHistory[switchHistory.length - 1]; | ||
const videoNow = video.currentTime; | ||
if (prev) { | ||
prev.end = videoNow; | ||
} | ||
switchHistory.push({start: videoNow, end: null, quality}); | ||
} | ||
|
||
function checkStallResolution() { | ||
if (stallingAt !== null) { | ||
history.stallDuration += (performance.now() - stallingAt); | ||
stallingAt = null; | ||
} | ||
} | ||
} | ||
}); | ||
</script> | ||
<script src="../highlighter.js"></script> | ||
</body> | ||
</html> | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.