Chromium Code Reviews| Index: tools/perf/perf_tools/media_metrics.js |
| diff --git a/tools/perf/perf_tools/media_metrics.js b/tools/perf/perf_tools/media_metrics.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4772712ad1e6e559fc163b76a483dcdf539a6181 |
| --- /dev/null |
| +++ b/tools/perf/perf_tools/media_metrics.js |
| @@ -0,0 +1,142 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +// This file contains common utilities to find video/audio elements on a page |
| +// and collect metrics for each. |
| + |
| +(function() { |
| + // MediaMetric class responsible for collecting metrics on a media element. |
| + // It attaches required event listeners in order to collect different metrics. |
| + function MediaMetric(element) { |
|
nduca
2013/07/09 23:07:19
should a MediaMetricBase base class, a HTML5Media
shadi
2013/07/11 00:49:13
PTAL. I kept all fields common to any media metric
|
| + this.metrics = {}; |
| + this.info = {}; |
| + this.element = element; |
| + this.isHTML5 = element instanceof HTMLMediaElement; |
|
nduca
2013/07/09 23:07:19
this could be a getter on MediaMetric.
shadi
2013/07/11 00:49:13
This is avoided with subclasses.
|
| + // Listen to when a Telemetry 'Play' action gets called. |
| + this.element.addEventListener('willPlay', this.onWillPlay, false); |
| + if (this.isHTML5) |
| + this.initHTML5(); |
|
nduca
2013/07/09 23:07:19
what happens if you accidentally bind a media metr
shadi
2013/07/11 00:49:13
Done.
|
| + } |
|
nduca
2013/07/09 23:07:19
should you explode if this isnt' html5?
shadi
2013/07/11 00:49:13
not really. If there are no html5 elements in the
|
| + |
| + MediaMetric.prototype.onWillPlay = function() { |
| + this.ttp_timer = new Timer(); |
|
nduca
2013/07/09 23:07:19
name this fully
shadi
2013/07/11 00:49:13
Done.
|
| + }; |
| + |
| + MediaMetric.prototype.initHTML5 = function() { |
| + // Set the basic event handlers for HTML5 media element. |
| + var metric = this; |
| + function onVideoLoad(event) { |
| + // If a 'Play' action is performed, then ttp_time != undefined. |
| + if (metric.ttp_timer == undefined) |
| + metric.ttp_timer = new Timer(); |
| + } |
| + // For the cases where autoplay=true, and without a 'play' action, we want |
| + // to start ttp_timer at 'play' or 'loadedmetadata' events. |
| + this.element.addEventListener('play', onVideoLoad); |
| + this.element.addEventListener('loadedmetadata', onVideoLoad); |
| + this.element.addEventListener('playing', function(e) { |
| + metric.onPlaying(e); |
| + }); |
| + this.element.addEventListener('ended', function(e) { |
| + metric.onEnded(e); |
| + }); |
| + }; |
| + |
| + MediaMetric.prototype.onPlaying = function(event) { |
| + // Playing event can fire more than once if seeking. |
| + if (!this.metrics['ttp']) |
| + this.metrics['ttp'] = [this.ttp_timer.stop(), 'sec']; |
| + }; |
| + |
| + MediaMetric.prototype.onEnded = function(event) { |
| + this.metrics['playback_time'] = [this.ttp_timer.stop(), 'sec']; |
| + }; |
| + |
| + MediaMetric.prototype.getElementInfo = function() { |
| + // Return information about the media element for this metric. |
| + if (this.element.id) |
| + this.info['id'] = this.element.id; |
| + if (this.isHTML5) { |
| + // Add interesting media specific tags. |
| + if (this.element.src) |
| + this.info['src'] = this.element.src; |
| + } |
| + return this.info; |
| + }; |
| + |
| + MediaMetric.prototype.getMetrics = function() { |
| + // Returns all collected metrics for the element |
| + if (this.isHTML5) { |
| + this.metrics['decoded_frame_count'] = |
| + [this.element.webkitDecodedFrameCount, 'frames']; |
| + this.metrics['dropped_frame_count'] = |
| + [this.element.webkitDroppedFrameCount, 'frames']; |
| + this.metrics['decoded_video_bytes'] = |
| + [this.element.webkitVideoDecodedByteCount, 'bytes']; |
| + this.metrics['decoded_audio_bytes'] = |
| + [this.element.webkitAudioDecodedByteCount, 'bytes']; |
| + } |
| + return this.metrics; |
| + }; |
| + |
| + MediaMetric.prototype.getSummary = function() { |
| + return { |
| + 'info': this.getElementInfo(), |
| + 'metrics': this.getMetrics() |
| + }; |
| + }; |
| + |
| + function Timer() { |
|
nduca
2013/07/09 23:07:19
why does this not call start()?
and why not just
shadi
2013/07/11 00:49:13
It is usually the case where you need to start the
|
| + this.start_ = getCurrentTime(); |
| + this.times_ = []; |
| + } |
| + |
| + Timer.prototype = { |
| + start: function() { |
| + this.start_ = getCurrentTime(); |
| + }, |
| + |
| + stop: function() { |
| + // Store time logs in secs. |
| + var delta = (getCurrentTime() - this.start_) / 1000; |
| + this.times_.push(delta); |
| + return delta; |
| + } |
| + }; |
| + |
| + function LoadMediaMetrics() { |
|
nduca
2013/07/09 23:07:19
This isn't really loading. createMediaMetricsForDo
shadi
2013/07/11 00:49:13
Done.
|
| + // Searches for all video and audio elements on the page and creates a |
| + // corresponding media metric instance for each. |
| + var media = document.querySelectorAll('video, audio'); |
|
nduca
2013/07/09 23:07:19
mediaElements
shadi
2013/07/11 00:49:13
Done.
|
| + for (var i = 0; i < media.length; i++) { |
|
nduca
2013/07/09 23:07:19
one liners dont get {}
shadi
2013/07/11 00:49:13
Done.
|
| + mediaMetrics.push(new MediaMetric(media[i])); |
|
nduca
2013/07/09 23:07:19
explicitly say window.__mediaMetrics perhaps inste
shadi
2013/07/11 00:49:13
Done.
|
| + } |
| + } |
| + |
| + function getCurrentTime() { |
| + if (window.performance) |
| + return (performance.now || |
| + performance.mozNow || |
| + performance.msNow || |
| + performance.oNow || |
| + performance.webkitNow).call(window.performance); |
| + else |
| + return Date().getTime(); |
|
nduca
2013/07/09 23:07:19
Date.now()? does't create garbage...
shadi
2013/07/11 00:49:13
Done.
|
| + } |
| + |
| + function getAllMetrics() { |
| + // Returns a summary (info + metrics) for all media metrics. |
| + var metrics = []; |
| + for (var i = 0; i < mediaMetrics.length; i++) { |
|
nduca
2013/07/09 23:07:19
one line fors get no bracez
shadi
2013/07/11 00:49:13
Done.
|
| + metrics.push(mediaMetrics[i].getSummary()); |
| + } |
| + return metrics; |
| + } |
| + |
| + // Stores metrics for all media elements on the page upon loading. |
| + var mediaMetrics = []; |
| + window.__mediaMetrics = mediaMetrics; |
| + window.__getAllMetrics = getAllMetrics; |
| + LoadMediaMetrics(); |
|
nduca
2013/07/09 23:07:19
you should keep injection of the script separate f
shadi
2013/07/11 00:49:13
Is there a good reason for this? Is there a case w
|
| +})(); |