blob: 4c966101a78df59e7b195b01d4241f849df9f67b [file] [log] [blame]
/**
* Copyright (c) 2012 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 requires the functions defined in test_functions.js.
var gFingerprints = [];
var gDetectorInterval = null;
// Public interface.
/**
* Starts capturing frames from a video tag. The algorithm will fingerprint a
* a frame every now and then. After calling this function and running for a
* while (at least 200 ms) you will be able to call isVideoPlaying to see if
* we detected any video.
*
* @param {string} videoElementId The video element to analyze.
* @param {int} width The video element's width.
* @param {int} width The video element's height.
*
* @return {string} Returns ok-started to the test.
*/
//
function startDetection(videoElementId, width, height) {
var video = document.getElementById(videoElementId);
if (!video)
throw failTest('Could not find video element with id ' + videoElementId);
if (gDetectorInterval)
throw failTest('Detector is already running.');
var NUM_FINGERPRINTS_TO_SAVE = 5;
var canvas = document.createElement('canvas');
canvas.style.display = 'none';
gFingerprints = [];
gDetectorInterval = setInterval(function() {
var context = canvas.getContext('2d');
if (video.videoWidth == 0)
return; // The video element isn't playing anything.
captureFrame_(video, context, width, height);
gFingerprints.push(fingerprint_(context, width, height));
if (gFingerprints.length > NUM_FINGERPRINTS_TO_SAVE) {
gFingerprints.shift();
}
}, 100);
returnToTest('ok-started');
}
/**
* Checks if we have detected any video so far.
*
* @return {string} video-playing if we detected video, otherwise
* video-not-playing.
*/
function isVideoPlaying() {
// Video is considered to be playing if at least one finger print has changed
// since the oldest fingerprint. Even small blips in the pixel data will cause
// this check to pass. We only check for rough equality though to account for
// rounding errors.
try {
if (gFingerprints.length > 1) {
if (!allElementsRoughlyEqualTo_(gFingerprints, gFingerprints[0])) {
clearInterval(gDetectorInterval);
gDetectorInterval = null;
returnToTest('video-playing');
return;
}
}
} catch (exception) {
throw failTest('Failed to detect video: ' + exception.message);
}
returnToTest('video-not-playing');
}
/**
* Queries for the stream size (not necessarily the size at which the video tag
* is rendered).
*
* @param videoElementId The video element to check.
* @return {string} ok-<width>x<height>, e.g. ok-640x480 for VGA.
*/
function getStreamSize(videoElementId) {
var video = document.getElementById(videoElementId);
if (!video)
throw failTest('Could not find video element with id ' + videoElementId);
returnToTest('ok-' + video.videoWidth + 'x' + video.videoHeight);
}
// Internals.
/** @private */
function allElementsRoughlyEqualTo_(elements, element_to_compare) {
if (elements.length == 0)
return false;
var PIXEL_DIFF_TOLERANCE = 100;
for (var i = 0; i < elements.length; i++) {
if (Math.abs(elements[i] - element_to_compare) > PIXEL_DIFF_TOLERANCE) {
return false;
}
}
return true;
}
/** @private */
function captureFrame_(video, canvasContext, width, height) {
canvasContext.drawImage(video, 0, 0, width, height);
}
/** @private */
function fingerprint_(canvasContext, width, height) {
var imageData = canvasContext.getImageData(0, 0, width, height);
var pixels = imageData.data;
var fingerprint = 0;
for (var i = 0; i < pixels.length; i++) {
fingerprint += pixels[i];
}
return fingerprint;
}