From a78e3516a451cc04176b3d982f1dcb984fa89f32 Mon Sep 17 00:00:00 2001 From: Garrett Singer Date: Fri, 14 Apr 2017 15:26:22 -0400 Subject: [PATCH 1/5] Add getVideoPlaybackQuality API --- src/js/player.js | 16 ++++++++ src/js/tech/flash.js | 23 +++++++++++ src/js/tech/html5.js | 34 +++++++++++++++ test/api/api.js | 1 + test/unit/tech/flash.test.js | 79 +++++++++++++++++++++++++++++++++++ test/unit/tech/html5.test.js | 80 ++++++++++++++++++++++++++++++++++++ 6 files changed, 233 insertions(+) diff --git a/src/js/player.js b/src/js/player.js index 91f483778a..90e33f0d1e 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -2988,6 +2988,22 @@ class Player extends Component { } } + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see https://wicg.github.io/media-playback-quality/ + * + * @return {Object|undefined} + * An object with supported media playback quality metrics or undefined if there + * is no tech or the tech does not support it. + */ + getVideoPlaybackQuality() { + if (this.tech_ && this.tech_.getVideoPlaybackQuality) { + return this.tech_.getVideoPlaybackQuality(); + } + } + /** * Get video width * diff --git a/src/js/tech/flash.js b/src/js/tech/flash.js index 7ed1662010..2c2a45df3f 100644 --- a/src/js/tech/flash.js +++ b/src/js/tech/flash.js @@ -341,6 +341,29 @@ class Flash extends Tech { return false; } + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see https://wicg.github.io/media-playback-quality/ + * + * @return {Object} + * An object with supported media playback quality metrics + */ + getVideoPlaybackQuality() { + const videoPlaybackQuality = this.el_.vjs_getProperty('getVideoPlaybackQuality'); + + if (window.performance && typeof window.performance.now === 'function') { + videoPlaybackQuality.creationTime = window.performance.now(); + } else if (window.performance && + window.performance.timing && + typeof window.performance.timing.navigationStart === 'number') { + videoPlaybackQuality.creationTime = + window.Date.now() - window.performance.timing.navigationStart; + } + + return videoPlaybackQuality; + } } // Create setters and getters for attributes diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index a6d0d35557..faf0df56e1 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -794,6 +794,40 @@ class Html5 extends Tech { } } } + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see https://wicg.github.io/media-playback-quality/ + * + * @return {Object} + * An object with supported media playback quality metrics + */ + getVideoPlaybackQuality() { + if (typeof this.el().getVideoPlaybackQuality === 'function') { + return this.el().getVideoPlaybackQuality(); + } + + const videoPlaybackQuality = {}; + + if (typeof this.el().webkitDroppedFrameCount !== 'undefined' && + typeof this.el().webkitDecodedFrameCount !== 'undefined') { + videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount; + videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount; + } + + if (window.performance && typeof window.performance.now === 'function') { + videoPlaybackQuality.creationTime = window.performance.now(); + } else if (window.performance && + window.performance.timing && + typeof window.performance.timing.navigationStart === 'number') { + videoPlaybackQuality.creationTime = + window.Date.now() - window.performance.timing.navigationStart; + } + + return videoPlaybackQuality; + } } /* HTML5 Support Testing ---------------------------------------------------- */ diff --git a/test/api/api.js b/test/api/api.js index 62eb735b35..766d4b7cdf 100644 --- a/test/api/api.js +++ b/test/api/api.js @@ -59,6 +59,7 @@ QUnit.test('should be able to access expected player API methods', function(asse assert.ok(player.userActive, 'userActive exists'); assert.ok(player.usingNativeControls, 'usingNativeControls exists'); assert.ok(player.isFullscreen, 'isFullscreen exists'); + assert.ok(player.getVideoPlaybackQuality, 'getVideoPlaybackQuality exists'); // Track methods assert.ok(player.audioTracks, 'audioTracks exists'); diff --git a/test/unit/tech/flash.test.js b/test/unit/tech/flash.test.js index 96dcd7e2c2..2eaa5f99e3 100644 --- a/test/unit/tech/flash.test.js +++ b/test/unit/tech/flash.test.js @@ -2,6 +2,7 @@ import Flash from '../../../src/js/tech/flash.js'; import { createTimeRange } from '../../../src/js/utils/time-ranges.js'; import document from 'global/document'; +import window from 'global/window'; import sinon from 'sinon'; // fake out the interaction but leave all the other logic intact @@ -261,3 +262,81 @@ QUnit.test('duration returns NaN, Infinity or duration according to the HTML sta 'duration returns duration property when readyState' + ' and duration property are both higher than 0'); }); + +QUnit.test('getVideoPlaybackQuality API exists', function(assert) { + const propertyCalls = []; + const videoPlaybackQuality = { test: 'test' }; + const mockFlash = { + el_: { + /* eslint-disable camelcase */ + vjs_getProperty(attr) { + propertyCalls.push(attr); + return videoPlaybackQuality; + } + /* eslint-enable camelcase */ + } + }; + + assert.equal(typeof Flash.prototype.getVideoPlaybackQuality, + 'function', + 'getVideoPlaybackQuality is a function'); + assert.deepEqual(Flash.prototype.getVideoPlaybackQuality.call(mockFlash), + videoPlaybackQuality, + 'called to get property from flash'); + assert.equal(propertyCalls.length, 1, 'only one property call'); + assert.equal(propertyCalls[0], + 'getVideoPlaybackQuality', + 'called for getVideoPlaybackQuality'); +}); + +QUnit.test('getVideoPlaybackQuality uses best available creationTime', function(assert) { + const origPerformance = window.performance; + const origDate = window.Date; + const videoPlaybackQuality = {}; + const mockFlash = { + el_: { + /* eslint-disable camelcase */ + vjs_getProperty(attr) { + return videoPlaybackQuality; + } + /* eslint-enable camelcase */ + } + }; + + window.performance = void 0; + assert.notOk(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime, + 'no creationTime when no performance API available'); + + window.performance = { + timing: {} + }; + assert.notOk(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime, + 'no creationTime when performance API insufficient'); + + window.performance = { + now: () => 4 + }; + assert.equal(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime, + 4, + 'creationTime is performance.now when available'); + + window.Date = { + now: () => 10 + }; + window.performance = { + timing: { + navigationStart: 3 + } + }; + assert.equal(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime, + 7, + 'creationTime uses Date.now() - navigationStart when available'); + + window.performance.now = () => 4; + assert.equal(Flash.prototype.getVideoPlaybackQuality.call(mockFlash).creationTime, + 4, + 'creationTime prioritizes performance.now when available'); + + window.Date = origDate; + window.performance = origPerformance; +}); diff --git a/test/unit/tech/html5.test.js b/test/unit/tech/html5.test.js index 2d2a6eabc8..0b1fd7460b 100644 --- a/test/unit/tech/html5.test.js +++ b/test/unit/tech/html5.test.js @@ -641,3 +641,83 @@ test('When Android Chrome reports Infinity duration with currentTime 0, return N browser.IS_CHROME = oldIsChrome; tech.el_ = oldEl; }); + +QUnit.test('supports getting available media playback quality metrics', function(assert) { + const origPerformance = window.performance; + const origDate = window.Date; + const oldEl = tech.el_; + const videoPlaybackQuality = { + creationTime: 1, + corruptedVideoFrames: 2, + droppedVideoFrames: 3, + totalVideoFrames: 5 + }; + + tech.el_ = { + getVideoPlaybackQuality: () => videoPlaybackQuality + }; + assert.deepEqual(tech.getVideoPlaybackQuality(), + videoPlaybackQuality, + 'uses native implementation when supported'); + + tech.el_ = { + webkitDroppedFrameCount: 1, + webkitDecodedFrameCount: 2 + }; + window.performance = { + now: () => 4 + }; + assert.deepEqual(tech.getVideoPlaybackQuality(), + { droppedVideoFrames: 1, totalVideoFrames: 2, creationTime: 4 }, + 'uses webkit prefixed metrics and performance.now when supported'); + + tech.el_ = { + webkitDroppedFrameCount: 1, + webkitDecodedFrameCount: 2 + }; + window.Date = { + now: () => 10 + }; + window.performance = { + timing: { + navigationStart: 3 + } + }; + assert.deepEqual(tech.getVideoPlaybackQuality(), + { droppedVideoFrames: 1, totalVideoFrames: 2, creationTime: 7 }, + 'uses webkit prefixed metrics and Date.now() - navigationStart when ' + + 'supported'); + + tech.el_ = {}; + window.performance = void 0; + assert.deepEqual(tech.getVideoPlaybackQuality(), {}, 'empty object when not supported'); + + window.performance = { + now: () => 5 + }; + assert.deepEqual(tech.getVideoPlaybackQuality(), + { creationTime: 5 }, + 'only creation time when it\'s the only piece available'); + + window.performance = { + timing: { + navigationStart: 3 + } + }; + assert.deepEqual(tech.getVideoPlaybackQuality(), + { creationTime: 7 }, + 'only creation time when it\'s the only piece available'); + + tech.el_ = { + getVideoPlaybackQuality: () => videoPlaybackQuality, + webkitDroppedFrameCount: 1, + webkitDecodedFrameCount: 2 + }; + assert.deepEqual(tech.getVideoPlaybackQuality(), + videoPlaybackQuality, + 'prefers native implementation when supported'); + + tech.el_ = oldEl; + window.performance = origPerformance; + window.Date = origDate; +}); From 4ac211eb98ee7bb310c688939cb1a40f28e3e884 Mon Sep 17 00:00:00 2001 From: Garrett Singer Date: Thu, 20 Apr 2017 17:07:24 -0400 Subject: [PATCH 2/5] Use techGet in getVideoPlaybackQuality --- src/js/player.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/js/player.js b/src/js/player.js index 90e33f0d1e..9aed1c7db5 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -2999,9 +2999,7 @@ class Player extends Component { * is no tech or the tech does not support it. */ getVideoPlaybackQuality() { - if (this.tech_ && this.tech_.getVideoPlaybackQuality) { - return this.tech_.getVideoPlaybackQuality(); - } + return this.techGet_('getVideoPlaybackQuality'); } /** From 43a7914dc6278f93392016f9afcc6eb11abdbe8d Mon Sep 17 00:00:00 2001 From: Garrett Singer Date: Tue, 25 Apr 2017 10:44:42 -0400 Subject: [PATCH 3/5] Add abstract method on Tech for getVideoPlaybackQuality --- src/js/tech/tech.js | 15 +++++++++++++++ test/unit/tech/tech.test.js | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index 91fc7a8637..fafe1c6f6d 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -805,6 +805,21 @@ class Tech extends Component { this.autoRemoteTextTracks_.removeTrack_(track); } + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see https://wicg.github.io/media-playback-quality/ + * + * @return {Object} + * An object with supported media playback quality metrics + * + * @abstract + */ + getVideoPlaybackQuality() { + return {}; + } + /** * A method to set a poster from a `Tech`. * diff --git a/test/unit/tech/tech.test.js b/test/unit/tech/tech.test.js index 77db2d7b4b..4b4415b505 100644 --- a/test/unit/tech/tech.test.js +++ b/test/unit/tech/tech.test.js @@ -631,3 +631,9 @@ QUnit.test('setSource after previous setSource should dispose source handler onc }); +QUnit.test('returns an empty object for getVideoPlaybackQuality', function(assert) { + const tech = new Tech(); + + assert.deepEqual(tech.getVideoPlaybackQuality(), {}, 'returns an empty object'); +}); + From bf5d881bede84c4bd29d295feae3acc6325642d1 Mon Sep 17 00:00:00 2001 From: Garrett Singer Date: Mon, 8 May 2017 17:32:22 -0400 Subject: [PATCH 4/5] Update spec references for media-playback-quality --- src/js/player.js | 2 +- src/js/tech/flash.js | 2 +- src/js/tech/html5.js | 2 +- src/js/tech/tech.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/player.js b/src/js/player.js index 9aed1c7db5..3acd9972c4 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -2992,7 +2992,7 @@ class Player extends Component { * Gets available media playback quality metrics as specified by the W3C's Media * Playback Quality API. * - * @see https://wicg.github.io/media-playback-quality/ + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} * * @return {Object|undefined} * An object with supported media playback quality metrics or undefined if there diff --git a/src/js/tech/flash.js b/src/js/tech/flash.js index 2c2a45df3f..18fafd2b50 100644 --- a/src/js/tech/flash.js +++ b/src/js/tech/flash.js @@ -345,7 +345,7 @@ class Flash extends Tech { * Gets available media playback quality metrics as specified by the W3C's Media * Playback Quality API. * - * @see https://wicg.github.io/media-playback-quality/ + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} * * @return {Object} * An object with supported media playback quality metrics diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index faf0df56e1..58546eead5 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -799,7 +799,7 @@ class Html5 extends Tech { * Gets available media playback quality metrics as specified by the W3C's Media * Playback Quality API. * - * @see https://wicg.github.io/media-playback-quality/ + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} * * @return {Object} * An object with supported media playback quality metrics diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index fafe1c6f6d..90422152dd 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -809,7 +809,7 @@ class Tech extends Component { * Gets available media playback quality metrics as specified by the W3C's Media * Playback Quality API. * - * @see https://wicg.github.io/media-playback-quality/ + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} * * @return {Object} * An object with supported media playback quality metrics From c7f7b4567f6723a36b31564cd83591ad712666a6 Mon Sep 17 00:00:00 2001 From: Garrett Singer Date: Tue, 9 May 2017 12:02:42 -0400 Subject: [PATCH 5/5] Update videojs-swf to 5.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 292306145b..08b7a31737 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "tsml": "1.0.1", "videojs-font": "2.0.0", "videojs-ie8": "1.1.2", - "videojs-swf": "5.3.0", + "videojs-swf": "5.4.0", "videojs-vtt.js": "0.12.3", "xhr": "2.2.2" },