// 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.
"use strict";
(function() {
window.__eventReporter = {};
window.__testState = {};
var logger = new Logger();
window.__logger = logger;
var video_format = 'video/mp4; codecs="avc1.640028"';
var audio_format = 'audio/mp4; codecs="mp4a.40.2"';
var audio1MB = createAudioDef(
'http://localhost:8000/files/car-audio-1MB-trunc.mp4', 1048576, 65.875);
var video1MB = createVideoDef(
'http://localhost:8000/files/test-video-1MB.mp4', 1031034, 1.04);
// Utility functions.
function Logger() {
var logs = [];
this.log = function(log_string) {
logs.push(log_string);
};
this.toString = function() {
var output = '';
for (var i in logs)
output += logs[i];
return output;
}
}
function createAudioDef(src, size, duration) {
return {
type: 'audio',
format: audio_format,
size: size,
src: src,
duration: duration,
bps: Math.floor(size / duration)
};
}
function createVideoDef(src, size, duration) {
return {
type: 'video',
format: video_format,
size: size,
src: src,
duration: duration,
bps: Math.floor(size / duration)
};
}
function createMediaSource() {
if (typeof MediaSource !== 'undefined')
return new MediaSource();
else
return new WebKitMediaSource();
}
function createVideo() {
return document.createElement('video');
}
function setupVideoAndMs(onSourceopen) {
var temp_video = createVideo();
var ms = createMediaSource();
ms.addEventListener('webkitsourceopen', onSourceopen);
var ms_url = window.URL.createObjectURL(ms);
temp_video.src = ms_url;
return {
'video': temp_video,
'ms': ms
};
}
function XHRWrapper(file, onLoad, onError, start, length) {
self = this;
self.file = file;
self.onLoad = onLoad;
self.onError = onError;
self.start = start;
self.length = length;
this.getResponseData = function() {
var result = new Uint8Array(this.xhr.response);
if (start != null) {
return result.subarray(start, start + length);
}
return result;
};
this.abort = function() {
this.xhr.abort();
};
this.send = function() {
this.xhr.send();
};
this.xhr = new XMLHttpRequest();
this.xhr.open('GET', file, true);
this.xhr.addEventListener('load', function(e) {
self.onLoad(e);
});
this.xhr.addEventListener('error', function(e) {
logger.log('XHR errored.');
self.onError(e);
});
this.xhr.addEventListener('timeout', function(e) {
logger.log('XHR timed out.');
self.onError(e);
});
this.xhr.responseType = 'arraybuffer';
if (length != null) {
start = start || 0;
this.xhr.setRequestHeader(
'Range',
'bytes=' + start + '-' + (start + length - 1)
);
}
}
function approxEq(a, b) {
return Math.abs(a - b) < 0.5;
};
// MSE tests.
window.__testAttach = function() {
var ms = createMediaSource();
ms.addEventListener('webkitsourceopen', function() {
window.__eventReporter['sourceopen'] = true;
});
var video = document.getElementById('main_player');
video.src = window.URL.createObjectURL(ms);
video.load();
};
window.__testAddSourceBuffer = function() {
var vm = setupVideoAndMs(function() {
try {
var return_value = true;
return_value &= vm.ms.sourceBuffers.length === 0;
vm.ms.addSourceBuffer(audio_format);
return_value &= vm.ms.sourceBuffers.length === 1;
vm.ms.addSourceBuffer(video_format);
return_value &= vm.ms.sourceBuffers.length === 2;
window.__testState['addSourceBuffer'] = !!return_value;
}
catch (e) {
window.__testState['addSourceBuffer'] = false;
}
});
};
window.__testAddSupportedFormats = function() {
var formats = [
audio_format,
video_format,
];
var vm = setupVideoAndMs(function() {
for (var i = 0; i < formats.length; ++i) {
try {
vm.ms.addSourceBuffer(formats[i]);
} catch (e) {
window.__testState['addSupportedFormats'] = false;
return;
}
}
window.__testState['addSupportedFormats'] = true;
});
};
window.__testAddSourceBufferException = function() {
var vm = setupVideoAndMs(function() {
try {
vm.ms.addSourceBuffer('^^^');
window.__testState['addSourceBufferException'] = false;
return;
}
catch (e) {
if (e.code !== DOMException.NOT_SUPPORTED_ERR) {
window.__testState['addSourceBufferException'] = false;
return;
}
}
try {
var temp_media_source = new WebKitMediaSource();
temp_media_source.addSourceBuffer(audio_format);
window.__testState['addSourceBufferException'] = false;
return;
}
catch (e) {
if (e.code !== DOMException.INVALID_STATE_ERR) {
window.__testState['addSourceBufferException'] = false;
return;
}
}
window.__testState['addSourceBufferException'] = true;
});
};
window.__testInitialVideoState = function() {
var temp_video = createVideo();
var test_result = isNaN(temp_video.duration);
test_result &= temp_video.videoWidth === 0;
test_result &= temp_video.videoHeight === 0;
test_result &= temp_video.readyState === HTMLMediaElement.HAVE_NOTHING;
test_result &= temp_video.src === '';
test_result &= temp_video.currentSrc === '';
window.__testState['initialVideoState'] = !!test_result;
};
window.__testInitialMSState = function() {
var vm = setupVideoAndMs(
function() {
var test_result = true;
test_result = test_result && isNaN(vm.ms.duration);
test_result = test_result && vm.ms.readyState === 'open';
window.__testState['initialMSState'] = test_result;
});
};
function appendTestTemplate(
test_name, media, test_func, abort, start, length, offset) {
var vm = setupVideoAndMs(function() {
var sb = vm.ms.addSourceBuffer(media.format);
var xhr = new XHRWrapper(
media.src,
function(e) {
var response_data = xhr.getResponseData();
if (offset != null)
sb.timestampOffset = offset;
sb.append(response_data);
if (abort != null) {
sb.abort();
sb.append(response_data);
}
var test_result = test_func(sb, media);
window.__testState[test_name] = test_result;
},
function(e) {
window.__testState[test_name] = false;
}, start, length);
xhr.send();
});
}
function appendInnerTest(sb, media) {
return sb.buffered.length === 1 && sb.buffered.start(0) === 0 &&
approxEq(sb.buffered.end(0), media.duration);
}
window.__testAppend_audio = function() {
appendTestTemplate('append_audio', audio1MB, appendInnerTest);
};
window.__testAppend_video = function() {
appendTestTemplate('append_video', video1MB, appendInnerTest);
};
function appendAbortInnerTest(sb, media) {
return sb.buffered.length === 1 && sb.buffered.start(0) === 0 &&
sb.buffered.end(0) > 0;
}
window.__testAppendAbort_audio = function() {
appendTestTemplate(
'appendAbort_audio', audio1MB, appendAbortInnerTest, true, 0, 200000);
};
window.__testAppendAbort_video = function() {
appendTestTemplate(
'appendAbort_video', video1MB, appendAbortInnerTest, true, 0, 200000);
};
var TIMESTAMP_BUFFERED_OFFSET = 5;
function appendTimestampOffsetTest(sb, media) {
return sb.buffered.length === 1 &&
sb.buffered.start(0) === TIMESTAMP_BUFFERED_OFFSET &&
approxEq(sb.buffered.end(0), media.duration + TIMESTAMP_BUFFERED_OFFSET);
}
window.__testAppendTimestampOffset_audio = function() {
appendTestTemplate(
'appendTimestampOffset_audio', audio1MB, appendTimestampOffsetTest,
null, null, null, TIMESTAMP_BUFFERED_OFFSET);
};
window.__testAppendTimestampOffset_video = function() {
appendTestTemplate(
'appendTimestampOffset_video', video1MB, appendTimestampOffsetTest,
null, null, null, TIMESTAMP_BUFFERED_OFFSET);
};
window.__testDuration = function() {
var vm = setupVideoAndMs(
function() {
var DURATION_TIME = 10;
vm.ms.duration = DURATION_TIME;
window.setTimeout(function() {
window.__testState['duration'] = vm.ms.duration === DURATION_TIME;
}, 20);
});
};
function testDurationAfterAppend(test_name, media) {
var vm = setupVideoAndMs(function() {
var sb = vm.ms.addSourceBuffer(media.format);
function onDurationChange() {
window.__testState[test_name] = approxEq(
vm.ms.duration, sb.buffered.end(0));
}
var xhr = new XHRWrapper(media.src, function() {
var response_data = xhr.getResponseData();
sb.append(response_data);
sb.abort();
vm.ms.duration = sb.buffered.end(0) / 2;
vm.video.addEventListener('durationchange', onDurationChange);
sb.append(response_data);
});
xhr.send();
});
};
window.__testDurationAfterAppend_audio = function() {
testDurationAfterAppend('durationAfterAppend_audio', audio1MB);
};
window.__testDurationAfterAppend_video = function() {
testDurationAfterAppend('durationAfterAppend_video', video1MB);
};
window.__testSourceRemove = function() {
var vm = setupVideoAndMs(
function() {
var sbAudio = vm.ms.addSourceBuffer(audio_format);
var result = vm.ms.sourceBuffers.length === 1;
vm.ms.removeSourceBuffer(sbAudio);
result &= vm.ms.sourceBuffers.length === 0;
sbAudio = vm.ms.addSourceBuffer(audio_format);
result &= vm.ms.sourceBuffers.length === 1;
for (var i = 0; i < 10; ++i) {
var sbVideo = vm.ms.addSourceBuffer(video_format);
result &= vm.ms.sourceBuffers.length === 2;
vm.ms.removeSourceBuffer(sbVideo);
result &= vm.ms.sourceBuffers.length === 1;
}
vm.ms.removeSourceBuffer(sbAudio);
result &= vm.ms.sourceBuffers.length === 0;
window.__testState['sourceRemove'] = !!result;
});
};
// EME tests.
window.__testCanPlayWebM = function() {
var tempVideo = createVideo();
return tempVideo.canPlayType(
'video/webm; codecs="vp8,vorbis"') === 'probably' &&
tempVideo.canPlayType(
'audio/webm; codecs="vorbis"') === 'probably';
};
window.__testCanPlayClearKey = function() {
var tempVideo = createVideo();
return tempVideo.canPlayType(
'video/mp4; codecs="avc1.640028"',
'webkit-org.w3.clearkey') === 'probably' &&
tempVideo.canPlayType(
'audio/mp4; codecs="mp4a.40.2"',
'webkit-org.w3.clearkey') === 'probably';
};
window.__testCanNotPlayPlayReady = function() {
var tempVideo = createVideo();
return tempVideo.canPlayType(
'video/mp4; codecs="avc1.640028"',
'com.youtube.playready') !== 'probably' &&
tempVideo.canPlayType(
'audio/mp4; codecs="mp4a.40.2"',
'com.youtube.playready') !== 'probably';
};
window.__testCanPlayWidevine = function() {
function createWidevineTest(mediaType) {
var tempVideo = createVideo();
return function(codecs, keySystem, criteria) {
var codecString = mediaType;
if (codecs != null)
codecString += '; codecs="' + codecs + '"';
var testResult = tempVideo.canPlayType(codecString, keySystem);
if (criteria === null)
return testResult === 'probably' || testResult === 'maybe';
else if (typeof(criteria) === 'string')
return testResult === criteria;
else if (criteria.length) {
var checks = false;
for (var i in criteria)
checks |= testResult === criteria[i];
return !!checks;
}
return false;
}
}
var audioTest = createWidevineTest('audio/webm');
var videoTest = createWidevineTest('video/webm');
var result = true;
// Supported video formats.
result &= videoTest(null, 'com.widevine.alpha', 'maybe');
result &= videoTest(null, 'com.widevine', 'maybe');
result &= videoTest('vp8', 'com.widevine.alpha', 'probably');
result &= videoTest('vp8', 'com.widevine', 'probably');
result &= videoTest('vp8.0', 'com.widevine.alpha', 'probably');
result &= videoTest('vp8.0', 'com.widevine', 'probably');
result &= videoTest('vorbis', 'com.widevine.alpha', 'probably');
result &= videoTest('vorbis', 'com.widevine', 'probably');
result &= videoTest('vp8,vp8.0,vorbis', 'com.widevine.alpha', 'probably');
result &= videoTest('vp8,vp8.0,vorbis', 'com.widevine', 'probably');
// Supported audio formats.
result &= audioTest(null, 'com.widevine.alpha', 'maybe');
result &= audioTest(null, 'com.widevine', 'maybe');
result &= audioTest('vorbis', 'com.widevine.alpha', 'probably');
result &= audioTest('vorbis', 'com.widevine', 'probably');
// Unsupported video formats.
result &= videoTest('codecs="vp8"', 'com.widevine.', '');
result &= videoTest('codecs="vp8"', 'com.widevine.foo', '');
result &= videoTest('codecs="vp8"', 'com.widevine.alpha.', '');
result &= videoTest('codecs="vp8"', 'com.widevine.alpha.foo', '');
result &= videoTest('codecs="vp8"', 'com.widevine.alph', '');
result &= videoTest('codecs="vp8"', 'com.widevine.alphb', '');
result &= videoTest('codecs="vp8"', 'com.widevine.alphaa', '');
result &= videoTest('codecs="avc1.640028"', 'com.widevine.alpha', '');
result &= videoTest('codecs="mp4a"', 'com.widevine.alpha', '');
// Unsported audio formats.
result &= audioTest('codecs="vp8"', 'com.widevine', '');
result &= audioTest('codecs="vp8,vorbis"', 'com.widevine.alpha', '');
result &= audioTest('codecs="vp8,vorbis"', 'com.widevine.alpha', '');
return result;
};
})();