ed46564d by David LaPalomento

Graph bandwidth on the stats page

Fix the stats page to work with video.js 5. Get the measured bitrate graph updating in real time.
1 parent 83b4302b
......@@ -23,7 +23,9 @@
<!-- Media Sources plugin -->
<script src="../../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script>
<script>
videojs.MediaSource.webWorkerURI = '../../node_modules/videojs-contrib-media-sources/src/transmuxer_worker.js';
</script>
<!-- HLS plugin -->
<script src="../../src/videojs-hls.js"></script>
......@@ -77,12 +79,11 @@
</video>
<section class="stats">
<h2>Player Stats</h2>
<div class="segment-timeline"></div>
<dl>
<dt>Current Time:</dt>
<dd class="current-time-stat">0</dd>
<dt>Buffered:</dt>
<dd><span class="buffered-start-stat">-</span> - <span class="buffered-end-stat">-</span></dd>
<dd class="buffered-stat">-</dd>
<dt>Seekable:</dt>
<dd><span class="seekable-start-stat">-</span> - <span class="seekable-end-stat">-</span></dd>
<dt>Video Bitrate:</dt>
......@@ -90,10 +91,13 @@
<dt>Measured Bitrate:</dt>
<dd class="measured-bitrate-stat">0 kbps</dd>
</dl>
<h3>Bitrate Switching</h3>
<div class="switching-stats">
Once the player begins loading, you'll see information about the
operation of the adaptive quality switching here.
</div>
<h3>Timed Metadata</h3>
<div class="segment-timeline"></div>
</section>
<script src="stats.js"></script>
......@@ -107,8 +111,7 @@
// ------------
var currentTimeStat = document.querySelector('.current-time-stat');
var bufferedStartStat = document.querySelector('.buffered-start-stat');
var bufferedEndStat = document.querySelector('.buffered-end-stat');
var bufferedStat = document.querySelector('.buffered-stat');
var seekableStartStat = document.querySelector('.seekable-start-stat');
var seekableEndStat = document.querySelector('.seekable-end-stat');
var videoBitrateState = document.querySelector('.video-bitrate-stat');
......@@ -119,20 +122,17 @@
});
player.on('progress', function() {
var oldStart, oldEnd;
var bufferedText = '', oldStart, oldEnd, i;
// buffered
var buffered = player.buffered();
if (buffered.length) {
oldStart = bufferedStartStat.textContent;
if (buffered.start(0).toFixed(1) !== oldStart) {
bufferedStartStat.textContent = buffered.start(0).toFixed(1);
}
oldEnd = bufferedEndStat.textContent;
if (buffered.end(0).toFixed(1) !== oldEnd) {
bufferedEndStat.textContent = buffered.end(0).toFixed(1);
}
bufferedText += buffered.start(0) + ' - ' + buffered.end(0);
}
for (i = 1; i < buffered.length; i++) {
bufferedText += ', ' + buffered.start(i) + ' - ' + buffered.end(i);
}
bufferedStat.textContent = bufferedText;
// seekable
var seekable = player.seekable();
......@@ -149,14 +149,14 @@
}
// bitrates
var playlist = player.tech.hls.playlists.media();
var playlist = player.tech_.hls.playlists.media();
if (playlist && playlist.attributes && playlist.attributes.BANDWIDTH) {
videoBitrateState.textContent = (playlist.attributes.BANDWIDTH / 1024).toLocaleString(undefined, {
maximumFractionDigits: 1
}) + ' kbps';
}
if (player.tech.hls.bandwidth) {
measuredBitrateStat.textContent = (player.tech.hls.bandwidth / 1024).toLocaleString(undefined, {
if (player.tech_.hls.bandwidth) {
measuredBitrateStat.textContent = (player.tech_.hls.bandwidth / 1024).toLocaleString(undefined, {
maximumFractionDigits: 1
}) + ' kbps';
}
......
......@@ -4,10 +4,15 @@
}
.axis line,
.axis path,
.intersect {
.axis path {
fill: none;
stroke: #111;
}
.bitrates {
fill: none;
stroke: #000;
stroke: steelblue;
stroke-width: 3px;
}
.cue {
......@@ -23,6 +28,6 @@
.intersect {
fill: none;
stroke: #000;
stroke: #111;
stroke-dasharray: 2,2;
}
......
......@@ -7,9 +7,35 @@
var d3 = window.d3;
var setupGraph = function(element) {
element.innerHTML = '';
var bitrateTickFormatter = d3.format(',.0f');
var updateBitrateAxes = function(svg, xScale, yScale) {
var xAxis = d3.svg.axis().scale(xScale).orient('bottom');
svg.select('.axis.x')
.transition().duration(500)
.call(xAxis);
var yAxis = d3.svg.axis().scale(yScale)
.tickFormat(function(value) {
return bitrateTickFormatter(value / 1024);
}).orient('left');
svg.select('.axis.y')
.transition().duration(500)
.call(yAxis);
};
var updateBitrates = function(svg, x, y, measuredBitrateKbps) {
var bitrates, line;
bitrates = svg.selectAll('.bitrates').datum(measuredBitrateKbps);
line = d3.svg.line()
.x(function(bitrate) { return x(bitrate.time); })
.y(function(bitrate) { return y(bitrate.value); });
bitrates.transition().duration(500).attr('d', line);
};
var setupGraph = function(element, player) {
// setup the display
var margin = {
top: 20,
......@@ -30,15 +56,14 @@
var x = d3.time.scale().range([0, width]); // d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
x.domain([new Date(), new Date(Date.now() + (5 * 60 * 1000))]);
x.domain([new Date(), new Date(Date.now() + (1 * 60 * 1000))]);
y.domain([0, 5 * 1024 * 1024 * 8]);
var timeAxis = d3.svg.axis().scale(x).orient('bottom');
var tickFormatter = d3.format(',.0f');
var bitrateAxis = d3.svg.axis()
.scale(y)
.tickFormat(function(value) {
return tickFormatter(value / 1024);
return bitrateTickFormatter(value / 1024);
})
.orient('left');
......@@ -60,6 +85,26 @@
.style('text-anchor', 'end')
.text('Bitrate (kb/s)');
svg.append('path')
.attr('class', 'bitrates');
var measuredBitrateKbps = [{
time: new Date(),
value: player.tech_.hls.bandwidth || 0
}];
player.on('progress', function() {
measuredBitrateKbps.push({
time: new Date(),
value: player.tech_.hls.bandwidth || 0
});
x.domain([x.domain()[0], new Date()]);
y.domain([0, d3.max(measuredBitrateKbps, function(bitrate) {
return bitrate.value;
})]);
updateBitrateAxes(svg, x, y);
updateBitrates(svg, x, y, measuredBitrateKbps);
});
};
// ---------------
......@@ -86,8 +131,8 @@
var mediaDomain = function(media, player) {
var segments = media.segments;
var end = player.tech.hls.playlists.expiredPreDiscontinuity_;
end += player.tech.hls.playlists.expiredPostDiscontinuity_;
var end = player.tech_.hls.playlists.expiredPreDiscontinuity_;
end += player.tech_.hls.playlists.expiredPostDiscontinuity_;
end += Playlist.duration(media,
media.mediaSequence,
media.mediaSequence + segments.length);
......@@ -160,7 +205,7 @@
.call(ptsAxis);
};
var svgRenderSegmentTimeline = function(container, player) {
var media = player.tech.hls.playlists.media();
var media = player.tech_.hls.playlists.media();
var segments = media.segments; // media.segments.slice(0, count);
// setup the display
......@@ -196,7 +241,7 @@
// update everything on progress
player.on('progress', function() {
var updatedMedia = player.tech.hls.playlists.media();
var updatedMedia = player.tech_.hls.playlists.media();
var segments = updatedMedia.segments; // updatedMedia.segments.slice(currentIndex, currentIndex + count);
if (updatedMedia.mediaSequence !== media.mediaSequence) {
......@@ -220,7 +265,7 @@
};
var displayCues = function(container, player) {
var media = player.tech.hls.playlists.media();
var media = player.tech_.hls.playlists.media();
if (media && media.segments) {
svgRenderSegmentTimeline(container, player);
} else {
......