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 @@ ...@@ -23,7 +23,9 @@
23 23
24 <!-- Media Sources plugin --> 24 <!-- Media Sources plugin -->
25 <script src="../../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> 25 <script src="../../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script>
26 26 <script>
27 videojs.MediaSource.webWorkerURI = '../../node_modules/videojs-contrib-media-sources/src/transmuxer_worker.js';
28 </script>
27 <!-- HLS plugin --> 29 <!-- HLS plugin -->
28 <script src="../../src/videojs-hls.js"></script> 30 <script src="../../src/videojs-hls.js"></script>
29 31
...@@ -77,12 +79,11 @@ ...@@ -77,12 +79,11 @@
77 </video> 79 </video>
78 <section class="stats"> 80 <section class="stats">
79 <h2>Player Stats</h2> 81 <h2>Player Stats</h2>
80 <div class="segment-timeline"></div>
81 <dl> 82 <dl>
82 <dt>Current Time:</dt> 83 <dt>Current Time:</dt>
83 <dd class="current-time-stat">0</dd> 84 <dd class="current-time-stat">0</dd>
84 <dt>Buffered:</dt> 85 <dt>Buffered:</dt>
85 <dd><span class="buffered-start-stat">-</span> - <span class="buffered-end-stat">-</span></dd> 86 <dd class="buffered-stat">-</dd>
86 <dt>Seekable:</dt> 87 <dt>Seekable:</dt>
87 <dd><span class="seekable-start-stat">-</span> - <span class="seekable-end-stat">-</span></dd> 88 <dd><span class="seekable-start-stat">-</span> - <span class="seekable-end-stat">-</span></dd>
88 <dt>Video Bitrate:</dt> 89 <dt>Video Bitrate:</dt>
...@@ -90,10 +91,13 @@ ...@@ -90,10 +91,13 @@
90 <dt>Measured Bitrate:</dt> 91 <dt>Measured Bitrate:</dt>
91 <dd class="measured-bitrate-stat">0 kbps</dd> 92 <dd class="measured-bitrate-stat">0 kbps</dd>
92 </dl> 93 </dl>
94 <h3>Bitrate Switching</h3>
93 <div class="switching-stats"> 95 <div class="switching-stats">
94 Once the player begins loading, you'll see information about the 96 Once the player begins loading, you'll see information about the
95 operation of the adaptive quality switching here. 97 operation of the adaptive quality switching here.
96 </div> 98 </div>
99 <h3>Timed Metadata</h3>
100 <div class="segment-timeline"></div>
97 </section> 101 </section>
98 102
99 <script src="stats.js"></script> 103 <script src="stats.js"></script>
...@@ -107,8 +111,7 @@ ...@@ -107,8 +111,7 @@
107 // ------------ 111 // ------------
108 112
109 var currentTimeStat = document.querySelector('.current-time-stat'); 113 var currentTimeStat = document.querySelector('.current-time-stat');
110 var bufferedStartStat = document.querySelector('.buffered-start-stat'); 114 var bufferedStat = document.querySelector('.buffered-stat');
111 var bufferedEndStat = document.querySelector('.buffered-end-stat');
112 var seekableStartStat = document.querySelector('.seekable-start-stat'); 115 var seekableStartStat = document.querySelector('.seekable-start-stat');
113 var seekableEndStat = document.querySelector('.seekable-end-stat'); 116 var seekableEndStat = document.querySelector('.seekable-end-stat');
114 var videoBitrateState = document.querySelector('.video-bitrate-stat'); 117 var videoBitrateState = document.querySelector('.video-bitrate-stat');
...@@ -119,20 +122,17 @@ ...@@ -119,20 +122,17 @@
119 }); 122 });
120 123
121 player.on('progress', function() { 124 player.on('progress', function() {
122 var oldStart, oldEnd; 125 var bufferedText = '', oldStart, oldEnd, i;
126
123 // buffered 127 // buffered
124 var buffered = player.buffered(); 128 var buffered = player.buffered();
125 if (buffered.length) { 129 if (buffered.length) {
126 130 bufferedText += buffered.start(0) + ' - ' + buffered.end(0);
127 oldStart = bufferedStartStat.textContent; 131 }
128 if (buffered.start(0).toFixed(1) !== oldStart) { 132 for (i = 1; i < buffered.length; i++) {
129 bufferedStartStat.textContent = buffered.start(0).toFixed(1); 133 bufferedText += ', ' + buffered.start(i) + ' - ' + buffered.end(i);
130 }
131 oldEnd = bufferedEndStat.textContent;
132 if (buffered.end(0).toFixed(1) !== oldEnd) {
133 bufferedEndStat.textContent = buffered.end(0).toFixed(1);
134 }
135 } 134 }
135 bufferedStat.textContent = bufferedText;
136 136
137 // seekable 137 // seekable
138 var seekable = player.seekable(); 138 var seekable = player.seekable();
...@@ -149,14 +149,14 @@ ...@@ -149,14 +149,14 @@
149 } 149 }
150 150
151 // bitrates 151 // bitrates
152 var playlist = player.tech.hls.playlists.media(); 152 var playlist = player.tech_.hls.playlists.media();
153 if (playlist && playlist.attributes && playlist.attributes.BANDWIDTH) { 153 if (playlist && playlist.attributes && playlist.attributes.BANDWIDTH) {
154 videoBitrateState.textContent = (playlist.attributes.BANDWIDTH / 1024).toLocaleString(undefined, { 154 videoBitrateState.textContent = (playlist.attributes.BANDWIDTH / 1024).toLocaleString(undefined, {
155 maximumFractionDigits: 1 155 maximumFractionDigits: 1
156 }) + ' kbps'; 156 }) + ' kbps';
157 } 157 }
158 if (player.tech.hls.bandwidth) { 158 if (player.tech_.hls.bandwidth) {
159 measuredBitrateStat.textContent = (player.tech.hls.bandwidth / 1024).toLocaleString(undefined, { 159 measuredBitrateStat.textContent = (player.tech_.hls.bandwidth / 1024).toLocaleString(undefined, {
160 maximumFractionDigits: 1 160 maximumFractionDigits: 1
161 }) + ' kbps'; 161 }) + ' kbps';
162 } 162 }
......
...@@ -4,10 +4,15 @@ ...@@ -4,10 +4,15 @@
4 } 4 }
5 5
6 .axis line, 6 .axis line,
7 .axis path, 7 .axis path {
8 .intersect { 8 fill: none;
9 stroke: #111;
10 }
11
12 .bitrates {
9 fill: none; 13 fill: none;
10 stroke: #000; 14 stroke: steelblue;
15 stroke-width: 3px;
11 } 16 }
12 17
13 .cue { 18 .cue {
...@@ -23,6 +28,6 @@ ...@@ -23,6 +28,6 @@
23 28
24 .intersect { 29 .intersect {
25 fill: none; 30 fill: none;
26 stroke: #000; 31 stroke: #111;
27 stroke-dasharray: 2,2; 32 stroke-dasharray: 2,2;
28 } 33 }
......
...@@ -7,9 +7,35 @@ ...@@ -7,9 +7,35 @@
7 7
8 var d3 = window.d3; 8 var d3 = window.d3;
9 9
10 var setupGraph = function(element) { 10 var bitrateTickFormatter = d3.format(',.0f');
11 element.innerHTML = '';
12 11
12 var updateBitrateAxes = function(svg, xScale, yScale) {
13 var xAxis = d3.svg.axis().scale(xScale).orient('bottom');
14 svg.select('.axis.x')
15 .transition().duration(500)
16 .call(xAxis);
17
18 var yAxis = d3.svg.axis().scale(yScale)
19 .tickFormat(function(value) {
20 return bitrateTickFormatter(value / 1024);
21 }).orient('left');
22 svg.select('.axis.y')
23 .transition().duration(500)
24 .call(yAxis);
25 };
26
27 var updateBitrates = function(svg, x, y, measuredBitrateKbps) {
28 var bitrates, line;
29
30 bitrates = svg.selectAll('.bitrates').datum(measuredBitrateKbps);
31 line = d3.svg.line()
32 .x(function(bitrate) { return x(bitrate.time); })
33 .y(function(bitrate) { return y(bitrate.value); });
34
35 bitrates.transition().duration(500).attr('d', line);
36 };
37
38 var setupGraph = function(element, player) {
13 // setup the display 39 // setup the display
14 var margin = { 40 var margin = {
15 top: 20, 41 top: 20,
...@@ -30,15 +56,14 @@ ...@@ -30,15 +56,14 @@
30 var x = d3.time.scale().range([0, width]); // d3.scale.linear().range([0, width]); 56 var x = d3.time.scale().range([0, width]); // d3.scale.linear().range([0, width]);
31 var y = d3.scale.linear().range([height, 0]); 57 var y = d3.scale.linear().range([height, 0]);
32 58
33 x.domain([new Date(), new Date(Date.now() + (5 * 60 * 1000))]); 59 x.domain([new Date(), new Date(Date.now() + (1 * 60 * 1000))]);
34 y.domain([0, 5 * 1024 * 1024 * 8]); 60 y.domain([0, 5 * 1024 * 1024 * 8]);
35 61
36 var timeAxis = d3.svg.axis().scale(x).orient('bottom'); 62 var timeAxis = d3.svg.axis().scale(x).orient('bottom');
37 var tickFormatter = d3.format(',.0f');
38 var bitrateAxis = d3.svg.axis() 63 var bitrateAxis = d3.svg.axis()
39 .scale(y) 64 .scale(y)
40 .tickFormat(function(value) { 65 .tickFormat(function(value) {
41 return tickFormatter(value / 1024); 66 return bitrateTickFormatter(value / 1024);
42 }) 67 })
43 .orient('left'); 68 .orient('left');
44 69
...@@ -60,6 +85,26 @@ ...@@ -60,6 +85,26 @@
60 .style('text-anchor', 'end') 85 .style('text-anchor', 'end')
61 .text('Bitrate (kb/s)'); 86 .text('Bitrate (kb/s)');
62 87
88 svg.append('path')
89 .attr('class', 'bitrates');
90
91 var measuredBitrateKbps = [{
92 time: new Date(),
93 value: player.tech_.hls.bandwidth || 0
94 }];
95
96 player.on('progress', function() {
97 measuredBitrateKbps.push({
98 time: new Date(),
99 value: player.tech_.hls.bandwidth || 0
100 });
101 x.domain([x.domain()[0], new Date()]);
102 y.domain([0, d3.max(measuredBitrateKbps, function(bitrate) {
103 return bitrate.value;
104 })]);
105 updateBitrateAxes(svg, x, y);
106 updateBitrates(svg, x, y, measuredBitrateKbps);
107 });
63 }; 108 };
64 109
65 // --------------- 110 // ---------------
...@@ -86,8 +131,8 @@ ...@@ -86,8 +131,8 @@
86 131
87 var mediaDomain = function(media, player) { 132 var mediaDomain = function(media, player) {
88 var segments = media.segments; 133 var segments = media.segments;
89 var end = player.tech.hls.playlists.expiredPreDiscontinuity_; 134 var end = player.tech_.hls.playlists.expiredPreDiscontinuity_;
90 end += player.tech.hls.playlists.expiredPostDiscontinuity_; 135 end += player.tech_.hls.playlists.expiredPostDiscontinuity_;
91 end += Playlist.duration(media, 136 end += Playlist.duration(media,
92 media.mediaSequence, 137 media.mediaSequence,
93 media.mediaSequence + segments.length); 138 media.mediaSequence + segments.length);
...@@ -160,7 +205,7 @@ ...@@ -160,7 +205,7 @@
160 .call(ptsAxis); 205 .call(ptsAxis);
161 }; 206 };
162 var svgRenderSegmentTimeline = function(container, player) { 207 var svgRenderSegmentTimeline = function(container, player) {
163 var media = player.tech.hls.playlists.media(); 208 var media = player.tech_.hls.playlists.media();
164 var segments = media.segments; // media.segments.slice(0, count); 209 var segments = media.segments; // media.segments.slice(0, count);
165 210
166 // setup the display 211 // setup the display
...@@ -196,7 +241,7 @@ ...@@ -196,7 +241,7 @@
196 241
197 // update everything on progress 242 // update everything on progress
198 player.on('progress', function() { 243 player.on('progress', function() {
199 var updatedMedia = player.tech.hls.playlists.media(); 244 var updatedMedia = player.tech_.hls.playlists.media();
200 var segments = updatedMedia.segments; // updatedMedia.segments.slice(currentIndex, currentIndex + count); 245 var segments = updatedMedia.segments; // updatedMedia.segments.slice(currentIndex, currentIndex + count);
201 246
202 if (updatedMedia.mediaSequence !== media.mediaSequence) { 247 if (updatedMedia.mediaSequence !== media.mediaSequence) {
...@@ -220,7 +265,7 @@ ...@@ -220,7 +265,7 @@
220 }; 265 };
221 266
222 var displayCues = function(container, player) { 267 var displayCues = function(container, player) {
223 var media = player.tech.hls.playlists.media(); 268 var media = player.tech_.hls.playlists.media();
224 if (media && media.segments) { 269 if (media && media.segments) {
225 svgRenderSegmentTimeline(container, player); 270 svgRenderSegmentTimeline(container, player);
226 } else { 271 } else {
......