Update web-platform-tests to revision 0d318188757a9c996e20b82db201fd04de5aa255

This commit is contained in:
James Graham 2015-03-27 09:15:38 +00:00
parent b2a5225831
commit 1a81b18b9f
12321 changed files with 544385 additions and 6 deletions

View file

@ -0,0 +1,71 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>SourceBuffer#abort() when readyState attribute is not in the "open"</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
var contents = {'/media/white.webm': 'video/webm; codecs="vorbis,vp8"',
'/media/white.mp4' : 'video/mp4'};
//check the browser supports the MIME used in this test
function isTypeSupported(mime) {
if(!MediaSource.isTypeSupported(mime)) {
this.step(function() {
assert_unreached("Browser doesn't support the MIME used in this test: " + mime);
});
this.done();
return false;
}
return true;
}
function GET(url, processBody) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.send();
xhr.onload = function(e) {
if (xhr.status != 200) {
alert("Unexpected status code " + xhr.status + " for " + url);
return false;
}
processBody(new Uint8Array(xhr.response));
};
}
function mediaTest(file, mime) {
async_test(function(t) {
if(!isTypeSupported.bind(t)(mime)) {
return;
}
GET(file, function(data) {
var mediaSource = new MediaSource();
var sourceBuffer = null;
mediaSource.addEventListener('sourceopen', function(e) {
sourceBuffer = mediaSource.addSourceBuffer(mime);
mediaSource.endOfStream();
assert_equals(mediaSource.readyState, 'ended',
'mediaSource.readyState is "ended" after endOfStream()');
});
mediaSource.addEventListener('sourceended', t.step_func_done(function(e) {
assert_throws({name: 'InvalidStateError'}, function() {
sourceBuffer.abort();
});
}));
var video = document.createElement('video');
video.src = window.URL.createObjectURL(mediaSource);
});
}, 'SourceBuffer#abort() (' + mime + ') : If the readyState attribute ' +
'of the parent media source is not in the "open" state then throw ' +
'an INVALID_STATE_ERR exception and abort these steps.');
}
for(var file in contents) {
mediaTest(file, contents[file]);
}
</script>
</body>
</html>

View file

@ -0,0 +1,52 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>SourceBuffer#abort() for already removed buffer from parent media source</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
var mimes = ['video/webm; codecs="vorbis,vp8"', 'video/mp4'];
//check the browser supports the MIME used in this test
function isTypeSupported(mime) {
if(!MediaSource.isTypeSupported(mime)) {
this.step(function() {
assert_unreached("Browser doesn't support the MIME used in this test: " + mime);
});
this.done();
return false;
}
return true;
}
function mediaTest(mime) {
async_test(function(t) {
if(!isTypeSupported.bind(t)(mime)) {
return;
}
var mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', t.step_func_done(function(e) {
var sourceBuffer = mediaSource.addSourceBuffer(mime);
mediaSource.removeSourceBuffer(sourceBuffer);
assert_throws({name: 'InvalidStateError'},
function() {
sourceBuffer.abort();
},
'SourceBuffer#abort() after removing the SourceBuffer object');
}), false);
var video = document.createElement('video');
video.src = window.URL.createObjectURL(mediaSource);
}, 'SourceBuffer#abort (' + mime + ') : ' +
'if this object has been removed from the sourceBuffers attribute of the parent media source, ' +
'then throw an INVALID_STATE_ERR exception and abort these steps.');
}
mimes.forEach(function(mime) {
mediaTest(mime);
});
</script>
</body>
</html>

View file

@ -0,0 +1,92 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>Check SourceBuffer#abort() when the updating attribute is true</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
var contents = {'/media/white.webm': 'video/webm; codecs="vorbis,vp8"',
'/media/white.mp4' : 'video/mp4'};
function GET(url, processBody) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.send();
xhr.onload = function(e) {
if (xhr.status != 200) {
alert("Unexpected status code " + xhr.status + " for " + url);
return false;
}
processBody(new Uint8Array(xhr.response));
};
}
//check the browser supports the MIME used in this test
function isTypeSupported(mime) {
if(!MediaSource.isTypeSupported(mime)) {
this.step(function() {
assert_unreached("Browser doesn't support the MIME used in this test: " + mime);
});
this.done();
return false;
}
return true;
}
function mediaTest(file, mime) {
async_test(function(t) {
if(!isTypeSupported.bind(t)(mime)) {
return;
}
GET(file, function(data) {
var mediaSource = new MediaSource();
var num_updateend = 0;
var events = [];
mediaSource.addEventListener('sourceopen', t.step_func(function(e) {
var sourceBuffer = mediaSource.addSourceBuffer(mime);
assert_equals(sourceBuffer.updating, false);
sourceBuffer.addEventListener('updatestart', t.step_func(function(e) {
events.push('updatestart');
//abort when sourceBuffer#updating is true
sourceBuffer.abort();
assert_equals(sourceBuffer.updating, false,
'Check updating value after calling abort.');
assert_equals(sourceBuffer.appendWindowStart, 0);
assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY);
}));
sourceBuffer.addEventListener('update', t.step_func(function(e) {
assert_unreached("Can't touch this");
}));
sourceBuffer.addEventListener('updateend', function(e) {
events.push('updateend');
mediaSource.endOfStream();
});
sourceBuffer.addEventListener('abort', function(e) {
events.push('abort');
});
sourceBuffer.addEventListener('error', t.step_func(function(e) {
assert_unreached("Can't touch this");
}));
sourceBuffer.appendBuffer(data);
}));
mediaSource.addEventListener('sourceended', t.step_func_done(function(e) {
assert_array_equals(events,
['updatestart', 'abort', 'updateend'],
'Check the sequence of fired events.');
}));
var video = document.createElement('video');
video.src = window.URL.createObjectURL(mediaSource);
});
}, 'SourceBuffer#abort() (' + mime + ') : Check the algorithm when the updating attribute is true.');
}
for(var file in contents) {
mediaTest(file, contents[file]);
}
</script>
</body>
</html>

View file

@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>Check the values of appendWindowStart and appendWindowEnd after abort()</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
var mimes = ['video/webm; codecs="vorbis,vp8"', 'video/mp4'];
mimes.forEach(function(mime) {
async_test(function() {
assert_true(MediaSource.isTypeSupported(mime),
"Browser doesn't support the MIME used in this test: " + mime);
var mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', this.step_func_done(function(e) {
var sourceBuffer = mediaSource.addSourceBuffer(mime);
sourceBuffer.abort();
assert_equals(sourceBuffer.appendWindowStart, 0);
assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY);
}));
var video = document.createElement('video');
video.src = window.URL.createObjectURL(mediaSource);
}, 'SourceBuffer#abort() (' + mime + '): Check the values of appendWindowStart and appendWindowEnd.');
});
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>URL.createObjectURL(null)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
test(function() {
assert_throws(new TypeError(), function() {
window.URL.createObjectURL(null);
});
}, "URL.createObjectURL(null)");
</script>
</body>
</html>

View file

@ -0,0 +1,22 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>Revoking a created URL with URL.revokeObjectURL(url)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
var video = document.createElement('video');
test(function() {
var mediaSource = new MediaSource();
var url = window.URL.createObjectURL(mediaSource);
window.URL.revokeObjectURL(url);
video.src = url;
assert_equals(mediaSource.readyState, 'closed');
}, "Check revoking behavior of URL.revokeObjectURL(url).");
</script>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>URL.createObjectURL(mediaSource)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
test(function() {
var mediaSource = new MediaSource();
var url = window.URL.createObjectURL(mediaSource);
assert_true(url != null);
assert_true(url.match(/^blob:.+/) != null);
}, "URL.createObjectURL(mediaSource) should return a unique Blob URI.");
</script>
</body>
</html>

View file

@ -0,0 +1,52 @@
#!/bin/bash
if [ $# -lt 1 ]
then
echo "Usage: $0 <Blink directory>"
exit -1
fi
BLINK_ROOT=$1
LAYOUT_TEST_DIR=$BLINK_ROOT/LayoutTests
HTTP_MEDIA_TEST_DIR=$LAYOUT_TEST_DIR/http/tests/media
if [ ! -d "$BLINK_ROOT" ]
then
echo "$BLINK_ROOT is not a directory or doesn't exist"
exit -1
fi
if [ ! -d "$LAYOUT_TEST_DIR" ]
then
echo "$LAYOUT_TEST_DIR is not a directory or doesn't exist"
exit -1
fi
#rm -rf *.html *.js webm mp4 manifest.txt
cp $HTTP_MEDIA_TEST_DIR/media-source/mediasource-*.html $HTTP_MEDIA_TEST_DIR/media-source/mediasource-*.js .
cp -r $HTTP_MEDIA_TEST_DIR/resources/media-source/webm .
cp -r $HTTP_MEDIA_TEST_DIR/resources/media-source/mp4 .
# Remove Blink-specific files
rm mediasource-gc-after-decode-error-crash.html
sed -i 's/\/w3c\/resources\//\/resources\//g' *.html
sed -i 's/\/media\/resources\/media-source\///g' *.html
sed -i 's/\/media\/resources\/media-source\///g' *.js
sed -i 's/\/media\/resources\/media-source\///g' webm/*
for TEST_FILE in `ls *.html`
do
if [ "$TEST_FILE" = "index.html" ]
then
continue
fi
echo -e "$TEST_FILE" >> manifest.txt
done
cp import_tests-template.txt index.html
chmod -R a+r *.html *.js webm mp4 manifest.txt
chmod a+rx webm mp4

View file

@ -0,0 +1,93 @@
<!doctype html>
<html>
<head>
<link rel='stylesheet' href='/resources/testharness.css'>
<script>
(function() {
var testURLs = [];
var testIndex = 0;
var testCount = 0;
var STATUS_STRINGS = ["PASS", "FAIL", "TIMEOUT", "NOTRUN"];
function onMessage(e)
{
var testData = e.data;
//console.log(testData.type, testData);
if (testData.type == "complete") {
var tableBody = document.querySelector("#results tbody");
var fragment = document.createDocumentFragment();
testCount += testData.tests.length;
for (var i = 0; i < testData.tests.length; ++i) {
var testResults = testData.tests[i];
var tr = document.createElement("tr");
var status = document.createElement("td");
var testName = document.createElement("td");
var message = document.createElement("td");
status.textContent = STATUS_STRINGS[testResults.status];
tr.className = STATUS_STRINGS[testResults.status].toLowerCase();
testName.textContent = testResults.name;
message.textContent = testResults.message;
tr.appendChild(status);
tr.appendChild(testName);
tr.appendChild(message);
fragment.appendChild(tr);
}
testIndex++;
if (testIndex >= testURLs.length) {
return;
}
tableBody.appendChild(fragment);
startNextTest();
return;
}
}
function startNextTest()
{
var iframe = document.querySelector("iframe");
var testURL = testURLs[testIndex];
var tr = document.createElement("tr");
var td = document.createElement("td");
td.appendChild(document.createTextNode("Running tests in '" + testURL + "' :"));
td.colSpan = 3;
tr.appendChild(td);
document.querySelector("#results tbody").appendChild(tr);
iframe.src = testURL;
}
window["onBodyLoad"] = function()
{
window.addEventListener("message", onMessage);
var xhr = new XMLHttpRequest();
xhr.open("GET", "manifest.txt", false);
xhr.send();
var str = xhr.response.replace("\r", "");
testURLs = xhr.response.replace("\r", "").split("\n");
startNextTest();
}
})(window);
</script>
</head>
<body onload="onBodyLoad()">
<iframe></iframe>
<table id="results" style="float:left;">
<tbody>
</tbody>
</table>
<div id="log"></div>
</body>
</html>

View file

@ -0,0 +1,145 @@
<!doctype html>
<meta charset=utf-8>
<title>Media Source Extensions IDL tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
<script type=text/plain class=untested>
interface EventTarget {
void addEventListener(DOMString type, EventListener? callback, optional boolean capture /* = false */);
void removeEventListener(DOMString type, EventListener? callback, optional boolean capture /* = false */);
boolean dispatchEvent(Event event);
};
interface URL {};
interface HTMLVideoElement {};
interface AudioTrack {};
interface VideoTrack {};
interface TextTrack {};
interface TimeRanges {};
typedef double DOMHighResTimeStamp;
</script>
<script type=text/plain>
[Constructor]
interface MediaSource : EventTarget {
readonly attribute SourceBufferList sourceBuffers;
readonly attribute SourceBufferList activeSourceBuffers;
readonly attribute ReadyState readyState;
attribute unrestricted double duration;
SourceBuffer addSourceBuffer (DOMString type);
void removeSourceBuffer (SourceBuffer sourceBuffer);
void endOfStream (optional EndOfStreamError error);
static boolean isTypeSupported (DOMString type);
};
interface SourceBuffer : EventTarget {
attribute AppendMode mode;
readonly attribute boolean updating;
readonly attribute TimeRanges buffered;
attribute double timestampOffset;
readonly attribute AudioTrackList audioTracks;
readonly attribute VideoTrackList videoTracks;
readonly attribute TextTrackList textTracks;
attribute double appendWindowStart;
attribute unrestricted double appendWindowEnd;
void appendBuffer (ArrayBuffer data);
void appendBuffer (ArrayBufferView data);
void appendStream (Stream stream, [EnforceRange] optional unsigned long long maxSize);
void abort ();
void remove (double start, double end);
};
interface SourceBufferList : EventTarget {
readonly attribute unsigned long length;
getter SourceBuffer (unsigned long index);
};
interface VideoPlaybackQuality {
readonly attribute DOMHighResTimeStamp creationTime;
readonly attribute unsigned long totalVideoFrames;
readonly attribute unsigned long droppedVideoFrames;
readonly attribute unsigned long corruptedVideoFrames;
readonly attribute double totalFrameDelay;
};
partial interface URL {
static DOMString createObjectURL (MediaSource mediaSource);
};
partial interface HTMLVideoElement {
VideoPlaybackQuality getVideoPlaybackQuality ();
};
partial interface AudioTrack {
attribute DOMString kind;
attribute DOMString language;
readonly attribute SourceBuffer? sourceBuffer;
};
partial interface VideoTrack {
attribute DOMString kind;
attribute DOMString language;
readonly attribute SourceBuffer? sourceBuffer;
};
partial interface TextTrack {
attribute DOMString kind;
attribute DOMString language;
readonly attribute SourceBuffer? sourceBuffer;
};
enum EndOfStreamError {
"network",
"decode"
};
enum AppendMode {
"segments",
"sequence"
};
enum ReadyState {
"closed",
"open",
"ended"
};
</script>
<script>
"use strict";
var mediaSource;
var sourceBuffer;
var video = document.createElement("video");
var idlCheck = function() {
var idlArray = new IdlArray();
[].forEach.call(document.querySelectorAll("script[type=text\\/plain]"), function(node) {
if (node.className == "untested") {
idlArray.add_untested_idls(node.textContent);
} else {
idlArray.add_idls(node.textContent);
}
});
idlArray.add_objects({
MediaSource: ['mediaSource'],
SourceBuffer: ['sourceBuffer'],
SourceBufferList: ['mediaSource.sourceBuffers'],
VideoPlaybackQuality: ['video.getVideoPlaybackQuality()'],
});
idlArray.test();
}
mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener("sourceopen", function () {
var defaultType ='video/webm;codecs="vp8,vorbis"';
if (video.canPlayType(defaultType)) {
sourceBuffer = mediaSource.addSourceBuffer(defaultType);
} else {
sourceBuffer = mediaSource.addSourceBuffer('video/mp4');
}
sourceBuffer.addEventListener("updateend", function (e) {
mediaSource.endOfStream();
idlCheck();
});
sourceBuffer.appendBuffer(new ArrayBuffer());
});
</script>

View file

@ -0,0 +1,32 @@
mediasource-addsourcebuffer.html
mediasource-append-buffer.html
mediasource-appendwindow.html
mediasource-buffered.html
mediasource-closed.html
mediasource-config-change-mp4-a-bitrate.html
mediasource-config-change-mp4-av-audio-bitrate.html
mediasource-config-change-mp4-av-framesize.html
mediasource-config-change-mp4-av-video-bitrate.html
mediasource-config-change-mp4-v-bitrate.html
mediasource-config-change-mp4-v-framerate.html
mediasource-config-change-mp4-v-framesize.html
mediasource-config-change-webm-a-bitrate.html
mediasource-config-change-webm-av-audio-bitrate.html
mediasource-config-change-webm-av-framesize.html
mediasource-config-change-webm-av-video-bitrate.html
mediasource-config-change-webm-v-bitrate.html
mediasource-config-change-webm-v-framerate.html
mediasource-config-change-webm-v-framesize.html
mediasource-duration.html
mediasource-endofstream-invaliderror.html
mediasource-getvideoplaybackquality.html
mediasource-is-type-supported.html
mediasource-multiple-attach.html
mediasource-play.html
mediasource-play-then-seek-back.html
mediasource-redundant-seek.html
mediasource-remove.html
mediasource-seek-beyond-duration.html
mediasource-seek-during-pending-seek.html
mediasource-sourcebufferlist.html
mediasource-sourcebuffer-mode.html

View file

@ -0,0 +1,153 @@
<!DOCTYPE html>
<html>
<head>
<title>MediaSource.addSourceBuffer() test cases</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_test(function(test, mediaElement, mediaSource)
{
mediaSource.endOfStream();
assert_throws("InvalidStateError",
function() { mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE); },
"addSourceBuffer() threw an exception when in 'ended' state.");
test.done();
}, "Test addSourceBuffer() in 'ended' state.");
mediasource_test(function(test, mediaElement, mediaSource)
{
assert_throws("InvalidAccessError",
function() { mediaSource.addSourceBuffer(""); },
"addSourceBuffer() threw an exception when passed an empty string.");
test.done();
}, "Test addSourceBuffer() with empty type");
mediasource_test(function(test, mediaElement, mediaSource)
{
assert_throws("NotSupportedError",
function() { mediaSource.addSourceBuffer(null); },
"addSourceBuffer() threw an exception when passed null.");
test.done();
}, "Test addSourceBuffer() with null");
mediasource_test(function(test, mediaElement, mediaSource)
{
assert_throws("NotSupportedError",
function() { mediaSource.addSourceBuffer("invalidType"); },
"addSourceBuffer() threw an exception for an unsupported type.");
test.done();
}, "Test addSourceBuffer() with unsupported type");
mediasource_test(function(test, mediaElement, mediaSource)
{
var mimetype = 'video/webm;codecs="vp8,vorbis"';
assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is not in mediaSource.activeSourceBuffers");
test.done();
}, "Test addSourceBuffer() with Vorbis and VP8");
mediasource_test(function(test, mediaElement, mediaSource)
{
var videoMimetype = 'video/webm;codecs="vp8"';
var audioMimetype = 'audio/webm;codecs="vorbis"';
assert_true(MediaSource.isTypeSupported(videoMimetype), videoMimetype + " is supported");
assert_true(MediaSource.isTypeSupported(audioMimetype), audioMimetype + " is supported");
var sourceBufferA = mediaSource.addSourceBuffer(videoMimetype);
var sourceBufferB = mediaSource.addSourceBuffer(audioMimetype);
assert_equals(mediaSource.sourceBuffers[0], sourceBufferA, "sourceBufferA is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferA is not in mediaSource.activeSourceBuffers");
assert_equals(mediaSource.sourceBuffers[1], sourceBufferB, "sourceBufferB is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferB is not in mediaSource.activeSourceBuffers");
test.done();
}, "Test addSourceBuffer() with Vorbis and VP8 in separate SourceBuffers");
mediasource_test(function(test, mediaElement, mediaSource)
{
var mimetype = MediaSourceUtil.VIDEO_ONLY_TYPE;
assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is in mediaSource.activeSourceBuffers");
test.done();
}, "Test addSourceBuffer() video only");
mediasource_test(function(test, mediaElement, mediaSource)
{
var mimetype = MediaSourceUtil.AUDIO_ONLY_TYPE;
assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is in mediaSource.activeSourceBuffers");
test.done();
}, "Test addSourceBuffer() audio only");
mediasource_test(function(test, mediaElement, mediaSource)
{
var mimetype = 'video/mp4;codecs="avc1.4D4001,mp4a.40.2"';
assert_true(MediaSource.isTypeSupported(mimetype), mimetype + " is supported");
var sourceBuffer = mediaSource.addSourceBuffer(mimetype);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
assert_equals(mediaSource.sourceBuffers[0], sourceBuffer, "SourceBuffer is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBuffer is not in mediaSource.activeSourceBuffers");
test.done();
}, "Test addSourceBuffer() with AAC and H.264");
mediasource_test(function(test, mediaElement, mediaSource)
{
var videoMimetype = 'video/mp4;codecs="avc1.4D4001"';
var audioMimetype = 'audio/mp4;codecs="mp4a.40.2"';
assert_true(MediaSource.isTypeSupported(videoMimetype), videoMimetype + " is supported");
assert_true(MediaSource.isTypeSupported(audioMimetype), audioMimetype + " is supported");
var sourceBufferA = mediaSource.addSourceBuffer(videoMimetype);
var sourceBufferB = mediaSource.addSourceBuffer(audioMimetype);
assert_equals(mediaSource.sourceBuffers[0], sourceBufferA, "sourceBufferA is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferA is not in mediaSource.activeSourceBuffers");
assert_equals(mediaSource.sourceBuffers[1], sourceBufferB, "sourceBufferB is in mediaSource.sourceBuffers");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "SourceBufferB is not in mediaSource.activeSourceBuffers");
test.done();
}, "Test addSourceBuffer() with AAC and H.264 in separate SourceBuffers");
mediasource_test(function(test, mediaElement, mediaSource)
{
var reachedLimit = false;
// The 20 here is an arbitrary upper limit to make sure the test terminates. This test
// assumes that implementations won't support more than 20 SourceBuffers simultaneously.
for (var i = 0; i < 20; ++i) {
try {
mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
} catch(e) {
assert_equals(e.name, "QuotaExceededError");
reachedLimit = true;
break;
}
}
assert_true(reachedLimit, "Reached SourceBuffer limit.");
test.done();
}, "Test addSourceBuffer() QuotaExceededError.");
</script>
</body>
</html>

View file

@ -0,0 +1,538 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBuffer.appendBuffer() test cases</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test SourceBuffer.appendBuffer() event dispatching.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
assert_throws("InvalidStateError",
function() { sourceBuffer.appendBuffer(mediaData); },
"appendBuffer() throws an exception there is a pending append.");
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test SourceBuffer.appendBuffer() call during a pending appendBuffer().");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "abort", "Append aborted.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
sourceBuffer.abort();
assert_false(sourceBuffer.updating, "updating attribute is false");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test SourceBuffer.abort() call during a pending appendBuffer().");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.expectEvent(mediaSource, "sourceended", "MediaSource sourceended event");
mediaSource.endOfStream();
assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
test.expectEvent(mediaSource, "sourceopen", "MediaSource sourceopen event");
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
assert_true(sourceBuffer.updating, "updating attribute is true");
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test SourceBuffer.appendBuffer() triggering an 'ended' to 'open' transition.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.expectEvent(mediaSource, "sourceended", "MediaSource sourceended event");
mediaSource.endOfStream();
assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, "ended", "MediaSource readyState is 'ended'");
test.expectEvent(mediaSource, "sourceopen", "MediaSource sourceopen event");
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(new Uint8Array(0));
assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
assert_true(sourceBuffer.updating, "updating attribute is true");
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, "open", "MediaSource readyState is 'open'");
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test zero byte SourceBuffer.appendBuffer() call triggering an 'ended' to 'open' transition.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "abort", "Append aborted.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers.length");
test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "sourceBuffers");
mediaSource.removeSourceBuffer(sourceBuffer);
assert_false(sourceBuffer.updating, "updating attribute is false");
assert_throws("InvalidStateError",
function() { sourceBuffer.appendBuffer(mediaData); },
"appendBuffer() throws an exception because it isn't attached to the mediaSource anymore.");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test MediaSource.removeSourceBuffer() call during a pending appendBuffer().");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
assert_throws("InvalidStateError",
function() { mediaSource.duration = 1.0; },
"set duration throws an exception when updating attribute is true.");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test set MediaSource.duration during a pending appendBuffer() for one of its SourceBuffers.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, "error");
test.failOnEvent(mediaSource, "sourceended");
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
assert_throws("InvalidStateError",
function() { mediaSource.endOfStream(); },
"endOfStream() throws an exception when updating attribute is true.");
assert_equals(mediaSource.readyState, "open");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
assert_equals(mediaSource.readyState, "open");
test.done();
});
}, "Test MediaSource.endOfStream() during a pending appendBuffer() for one of its SourceBuffers.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
assert_throws("InvalidStateError",
function() { sourceBuffer.timestampOffset = 10.0; },
"set timestampOffset throws an exception when updating attribute is true.");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test set SourceBuffer.timestampOffset during a pending appendBuffer().");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(new Uint8Array(0));
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test appending an empty ArrayBufferView.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
var arrayBufferView = new Uint8Array(mediaData);
assert_equals(arrayBufferView.length, mediaData.length, "arrayBufferView.length before transfer.");
// Send the buffer as in a message so it gets neutered.
window.postMessage( "test", "*", [arrayBufferView.buffer]);
assert_equals(arrayBufferView.length, 0, "arrayBufferView.length after transfer.");
sourceBuffer.appendBuffer(arrayBufferView);
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test appending a neutered ArrayBufferView.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendBuffer(new ArrayBuffer(0));
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test appending an empty ArrayBuffer.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
var arrayBuffer = mediaData.buffer.slice(0);
assert_equals(arrayBuffer.byteLength, mediaData.buffer.byteLength, "arrayBuffer.byteLength before transfer.");
// Send the buffer as in a message so it gets neutered.
window.postMessage( "test", "*", [arrayBuffer]);
assert_equals(arrayBuffer.byteLength, 0, "arrayBuffer.byteLength after transfer.");
sourceBuffer.appendBuffer(arrayBuffer);
assert_true(sourceBuffer.updating, "updating attribute is true");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test appending a neutered ArrayBuffer.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var halfIndex = (initSegment.length + 1) / 2;
var partialInitSegment = initSegment.subarray(0, halfIndex);
var remainingInitSegment = initSegment.subarray(halfIndex);
var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
test.expectEvent(sourceBuffer, "updateend", "partialInitSegment append ended.");
sourceBuffer.appendBuffer(partialInitSegment);
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.readyState, mediaElement.HAVE_NOTHING);
assert_equals(mediaSource.duration, Number.NaN);
test.expectEvent(sourceBuffer, "updateend", "remainingInitSegment append ended.");
test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata event received.");
sourceBuffer.appendBuffer(remainingInitSegment);
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
assert_equals(mediaSource.duration, segmentInfo.duration);
test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
test.expectEvent(mediaElement, "loadeddata", "loadeddata fired.");
sourceBuffer.appendBuffer(mediaSegment);
});
test.waitForExpectedEvents(function()
{
assert_greater_than_equal(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA);
assert_equals(sourceBuffer.updating, false);
assert_equals(mediaSource.readyState, "open");
test.done();
});
}, "Test appendBuffer with partial init segments.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
var halfIndex = (mediaSegment.length + 1) / 2;
var partialMediaSegment = mediaSegment.subarray(0, halfIndex);
var remainingMediaSegment = mediaSegment.subarray(halfIndex);
test.expectEvent(sourceBuffer, "updateend", "InitSegment append ended.");
test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata done.");
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
assert_equals(mediaSource.duration, segmentInfo.duration);
test.expectEvent(sourceBuffer, "updateend", "partial media segment append ended.");
sourceBuffer.appendBuffer(partialMediaSegment);
});
test.waitForExpectedEvents(function()
{
test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
test.expectEvent(mediaElement, "loadeddata", "loadeddata fired.");
sourceBuffer.appendBuffer(remainingMediaSegment);
});
test.waitForExpectedEvents(function()
{
assert_greater_than_equal(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA);
assert_equals(mediaSource.readyState, "open");
assert_equals(sourceBuffer.updating, false);
test.done();
});
}, "Test appendBuffer with partial media segments.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var partialInitSegment = initSegment.subarray(0, initSegment.length / 2);
var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
test.expectEvent(sourceBuffer, "updateend", "partialInitSegment append ended.");
sourceBuffer.appendBuffer(partialInitSegment);
test.waitForExpectedEvents(function()
{
// Call abort to reset the parser.
sourceBuffer.abort();
// Append the full intiialization segment.
test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
sourceBuffer.appendBuffer(initSegment);
});
test.waitForExpectedEvents(function()
{
test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
test.expectEvent(mediaElement, "loadeddata", "loadeddata fired.");
sourceBuffer.appendBuffer(mediaSegment);
});
test.waitForExpectedEvents(function()
{
test.done();
});
}, "Test abort in the middle of an initialization segment.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "SourceBuffer removed.");
mediaSource.removeSourceBuffer(sourceBuffer);
test.waitForExpectedEvents(function()
{
assert_throws("InvalidStateError",
function() { sourceBuffer.abort(); },
"sourceBuffer.abort() throws an exception for InvalidStateError.");
test.done();
});
}, "Test abort after removing sourcebuffer.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, "open", "readyState is open after init segment appended.");
test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
sourceBuffer.appendBuffer(mediaSegment);
});
test.waitForExpectedEvents(function()
{
assert_equals(sourceBuffer.buffered.length, 1, "sourceBuffer has a buffered range");
assert_equals(mediaSource.readyState, "open", "readyState is open after media segment appended.");
test.expectEvent(mediaSource, "sourceended", "source ended");
mediaSource.endOfStream();
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, "ended", "readyState is ended.");
assert_throws("InvalidStateError",
function() { sourceBuffer.abort(); },
"sourceBuffer.abort() throws an exception for InvalidStateError.");
test.done();
});
}, "Test abort after readyState is ended following init segment and media segment.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
sourceBuffer.appendWindowStart = 1;
sourceBuffer.appendWindowEnd = 100;
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
sourceBuffer.abort();
assert_equals(sourceBuffer.appendWindowStart, 0, "appendWindowStart is reset to 0");
assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY,
"appendWindowEnd is reset to +INFINITY");
test.done();
});
}, "Test abort after appendBuffer update ends.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
test.expectEvent(sourceBuffer, "updatestart", "Append started.");
test.expectEvent(sourceBuffer, "update", "Append success.");
test.expectEvent(sourceBuffer, "updateend", "Append ended.");
assert_throws( { name: "TypeError"} ,
function() { sourceBuffer.appendBuffer(null); },
"appendBuffer(null) throws an exception.");
test.done();
}, "Test appending null.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaSource.removeSourceBuffer(sourceBuffer);
assert_throws( { name: "InvalidStateError"} ,
function() { sourceBuffer.appendBuffer(mediaData); },
"appendBuffer() throws an exception when called after removeSourceBuffer().");
test.done();
}, "Test appending after removeSourceBuffer().");
</script>
</body>
</html>

View file

@ -0,0 +1,175 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBuffer.appendWindowStart and SourceBuffer.appendWindowEnd test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
sourceBuffer.appendWindowStart = 100.0;
sourceBuffer.appendWindowEnd = 500.0;
assert_equals(sourceBuffer.appendWindowStart, 100.0, "appendWindowStart is correctly set'");
assert_equals(sourceBuffer.appendWindowEnd, 500.0, "appendWindowEnd is correctly set'");
sourceBuffer.appendWindowStart = 200.0;
sourceBuffer.appendWindowEnd = 400.0;
assert_equals(sourceBuffer.appendWindowStart, 200.0, "appendWindowStart is correctly reset'");
assert_equals(sourceBuffer.appendWindowEnd, 400.0, "appendWindowEnd is correctly reset'");
test.done();
}, "Test correctly reset appendWindowStart and appendWindowEnd values");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
sourceBuffer.appendWindowEnd = 500.0;
assert_throws(new TypeError(),
function() { sourceBuffer.appendWindowStart = Number.NEGATIVE_INFINITY; },
"set appendWindowStart throws an exception for Number.NEGATIVE_INFINITY.");
assert_throws(new TypeError(),
function() { sourceBuffer.appendWindowStart = Number.POSITIVE_INFINITY; },
"set appendWindowStart throws an exception for Number.POSITIVE_INFINITY.");
assert_throws(new TypeError(),
function() { sourceBuffer.appendWindowStart = Number.NaN; },
"set appendWindowStart throws an exception for Number.NaN.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowStart = 600.0; },
"set appendWindowStart throws an exception when greater than appendWindowEnd.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowStart = sourceBuffer.appendWindowEnd; },
"set appendWindowStart throws an exception when equal to appendWindowEnd.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowEnd = sourceBuffer.appendWindowStart; },
"set appendWindowEnd throws an exception when equal to appendWindowStart.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowEnd = sourceBuffer.appendWindowStart - 1; },
"set appendWindowEnd throws an exception if less than appendWindowStart.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowStart = -100.0; },
"set appendWindowStart throws an exception when less than 0.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowEnd = -100.0; },
"set appendWindowEnd throws an exception when less than 0.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowEnd = Number.NaN; },
"set appendWindowEnd throws an exception if NaN.");
assert_throws("InvalidAccessError",
function() { sourceBuffer.appendWindowEnd = undefined; },
"set appendWindowEnd throws an exception if undefined.");
assert_throws({name: "TypeError"},
function() { sourceBuffer.appendWindowStart = undefined; },
"set appendWindowStart throws an exception if undefined.");
test.done();
}, "Test set wrong values to appendWindowStart and appendWindowEnd.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
sourceBuffer.appendWindowStart = "";
assert_true(sourceBuffer.appendWindowStart == 0, "appendWindowStart is 0");
sourceBuffer.appendWindowStart = "10";
assert_true(sourceBuffer.appendWindowStart == 10, "appendWindowStart is 10");
sourceBuffer.appendWindowStart = null;
assert_true(sourceBuffer.appendWindowStart == 0, "appendWindowStart is 0");
sourceBuffer.appendWindowStart = true;
assert_true(sourceBuffer.appendWindowStart == 1, "appendWindowStart is 1");
sourceBuffer.appendWindowStart = false;
assert_true(sourceBuffer.appendWindowStart == 0, "appendWindowStart is 0");
sourceBuffer.appendWindowEnd = "100";
assert_true(sourceBuffer.appendWindowEnd == 100, "appendWindowEnd is 100");
test.done();
}, "Test set correct values to appendWindowStart and appendWindowEnd.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaSource.removeSourceBuffer(sourceBuffer);
assert_throws("InvalidStateError",
function() { sourceBuffer.appendWindowStart = 100.0; },
"set appendWindowStart throws an exception when mediasource object is not associated with a buffer.");
assert_throws("InvalidStateError",
function() { sourceBuffer.appendWindowEnd = 500.0; },
"set appendWindowEnd throws an exception when mediasource object is not associated with a buffer.");
test.done();
}, "Test appendwindow throw error when mediasource object is not associated with a sourebuffer.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updateend", "sourceBuffer");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
assert_throws("InvalidStateError",
function() { sourceBuffer.appendWindowStart = 100.0; },
"set appendWindowStart throws an exception when there is a pending append.");
assert_throws("InvalidStateError",
function() { sourceBuffer.appendWindowEnd = 500.0; },
"set appendWindowEnd throws an exception when there is a pending append.");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test set appendWindowStart and appendWindowEnd when source buffer updating.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updateend", "sourceBuffer");
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, "updating attribute is true");
sourceBuffer.abort();
assert_equals(sourceBuffer.appendWindowStart, 0, "appendWindowStart is 0 after an abort'");
assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY,
"appendWindowStart is POSITIVE_INFINITY after an abort");
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating attribute is false");
test.done();
});
}, "Test appendWindowStart and appendWindowEnd value after a sourceBuffer.abort().");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_equals(sourceBuffer.appendWindowStart, 0, "appendWindowStart is 0 initially");
assert_equals(sourceBuffer.appendWindowEnd, Number.POSITIVE_INFINITY,
"appendWindowStart is POSITIVE_INFINITY initially");
test.done();
}, "Test read appendWindowStart and appendWindowEnd initial values.");
</script>
</body>
</html>

View file

@ -0,0 +1,219 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBuffer.buffered test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
var subType = MediaSourceUtil.getSubType(MediaSourceUtil.AUDIO_ONLY_TYPE);
var manifestFilenameA = subType + "/test-a-128k-44100Hz-1ch-manifest.json";
var manifestFilenameB = subType + "/test-v-128k-320x240-30fps-10kfr-manifest.json";
var expectationsA = {
webm: "{ [0.000, 2.022) }",
mp4: "{ [0.000, 2.043) }",
};
var expectationsB = {
webm: "{ [0.000, 2.000) }",
mp4: "{ [0.000, 2.000) }",
};
function mediaSourceDemuxedTest(callback, description)
{
mediasource_test(function(test, mediaElement, mediaSource)
{
mediaElement.pause();
test.failOnEvent(mediaElement, "error");
test.endOnEvent(mediaElement, "ended");
MediaSourceUtil.fetchManifestAndData(test, manifestFilenameA, function(typeA, dataA)
{
MediaSourceUtil.fetchManifestAndData(test, manifestFilenameB, function(typeB, dataB)
{
mediaSource.addSourceBuffer(typeA);
mediaSource.addSourceBuffer(typeB);
assert_equals(mediaSource.sourceBuffers.length, 2);
callback(test, mediaElement, mediaSource, dataA, dataB);
});
});
}, description);
};
function appendData(test, mediaSource, dataA, dataB, callback)
{
var sourceBufferA = mediaSource.sourceBuffers[0];
var sourceBufferB = mediaSource.sourceBuffers[1];
test.expectEvent(sourceBufferA, "update");
test.expectEvent(sourceBufferA, "updateend");
sourceBufferA.appendBuffer(dataA);
test.expectEvent(sourceBufferB, "update");
test.expectEvent(sourceBufferB, "updateend");
sourceBufferB.appendBuffer(dataB);
test.waitForExpectedEvents(function()
{
callback();
});
}
mediaSourceDemuxedTest(function(test, mediaElement, mediaSource, dataA, dataB) {
test.expectEvent(mediaElement, "loadedmetadata");
appendData(test, mediaSource, dataA, dataB, function()
{
assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaSource.activeSourceBuffers[1], expectationsB[subType], "mediaSource.activeSourceBuffers[1]");
assertBufferedEquals(mediaElement, expectationsB[subType], "mediaElement.buffered");
mediaSource.endOfStream();
assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaSource.activeSourceBuffers[1], expectationsB[subType], "mediaSource.activeSourceBuffers[1]");
assertBufferedEquals(mediaElement, expectationsA[subType], "mediaElement.buffered");
test.done();
});
}, "Demuxed content with different lengths");
mediasource_test(function(test, mediaElement, mediaSource)
{
mediaElement.pause();
test.failOnEvent(mediaElement, "error");
test.endOnEvent(mediaElement, "ended");
MediaSourceUtil.fetchManifestAndData(test, subType + "/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json", function(type, data)
{
var sourceBuffer = mediaSource.addSourceBuffer(type);
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.appendBuffer(data);
test.waitForExpectedEvents(function()
{
var expectationsAV = {
webm: ["{ [0.000, 2.003) }", "{ [0.000, 2.022) }"],
mp4: ["{ [0.000, 2.000) }", "{ [0.000, 2.043) }"],
};
var expectedBeforeEndOfStream = expectationsAV[subType][0];
var expectedAfterEndOfStream = expectationsAV[subType][1];
assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectedBeforeEndOfStream, "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaElement, expectedBeforeEndOfStream, "mediaElement.buffered");
mediaSource.endOfStream();
assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectedAfterEndOfStream, "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaElement, expectedAfterEndOfStream, "mediaElement.buffered");
test.done();
});
});
}, "Muxed content with different lengths");
mediaSourceDemuxedTest(function(test, mediaElement, mediaSource, dataA, dataB) {
var dataBSize = {
webm: 318,
mp4: 835,
};
test.expectEvent(mediaElement, "loadedmetadata");
appendData(test, mediaSource, dataA, dataB.subarray(0, dataBSize[subType]), function()
{
assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaSource.activeSourceBuffers[1], "{ }", "mediaSource.activeSourceBuffers[1]");
assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
mediaSource.endOfStream();
assertBufferedEquals(mediaSource.activeSourceBuffers[0], expectationsA[subType], "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaSource.activeSourceBuffers[1], "{ }", "mediaSource.activeSourceBuffers[1]");
assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
test.done();
});
}, "Demuxed content with an empty buffered range on one SourceBuffer");
mediasource_test(function(test, mediaElement, mediaSource)
{
mediaElement.pause();
test.failOnEvent(mediaElement, "error");
test.endOnEvent(mediaElement, "ended");
MediaSourceUtil.fetchManifestAndData(test, subType + "/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr-manifest.json", function(type, data)
{
var sourceBuffer = mediaSource.addSourceBuffer(type);
test.expectEvent(mediaElement, "loadedmetadata");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.appendBuffer(data.subarray(0, 4052));
test.waitForExpectedEvents(function()
{
assertBufferedEquals(mediaSource.activeSourceBuffers[0], "{ }", "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
mediaSource.endOfStream();
assertBufferedEquals(mediaSource.activeSourceBuffers[0], "{ }", "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
test.done();
});
});
}, "Muxed content empty buffered ranges.");
mediasource_test(function(test, mediaElement, mediaSource)
{
mediaElement.pause();
test.failOnEvent(mediaElement, "error");
test.endOnEvent(mediaElement, "ended");
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
assertBufferedEquals(mediaSource.sourceBuffers[0], "{ }", "mediaSource.sourceBuffers[0]");
assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
test.done();
}, "Get buffered range when sourcebuffer is empty.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
test.expectEvent(mediaElement, "loadedmetadata");
test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assertBufferedEquals(mediaSource.sourceBuffers[0], "{ }", "mediaSource.sourceBuffers[0]");
assertBufferedEquals(mediaSource.activeSourceBuffers[0], "{ }", "mediaSource.activeSourceBuffers[0]");
assertBufferedEquals(mediaElement, "{ }", "mediaElement.buffered");
test.done();
});
}, "Get buffered range when only init segment is appended.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "SourceBuffer removed.");
mediaSource.removeSourceBuffer(sourceBuffer);
test.waitForExpectedEvents(function()
{
assert_throws("InvalidStateError",
function() { sourceBuffer.buffered; },
"get sourceBuffer.buffered throws an exception for InvalidStateError.");
test.done();
});
}, "Get buffered range after removing sourcebuffer.");
</script>
</body>
</html>

View file

@ -0,0 +1,139 @@
<!DOCTYPE html>
<html>
<head>
<title>MediaSource.readyState equals "closed" test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
test(function ()
{
var mediaSource = new MediaSource();
assert_equals(mediaSource.sourceBuffers.length, 0, "sourceBuffers is empty");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers is empty");
assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
assert_true(isNaN(mediaSource.duration), "duration is NaN");
}, "Test attribute values on a closed MediaSource object.");
test(function ()
{
var mediaSource = new MediaSource();
assert_throws("InvalidStateError",
function() { mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE); },
"addSourceBuffer() throws an exception when closed.");
}, "Test addSourceBuffer() while closed.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
// Setup a handler to run when the MediaSource closes.
mediaSource.addEventListener('sourceclose', test.step_func(function (event)
{
assert_equals(mediaSource.sourceBuffers.length, 0, "sourceBuffers is empty");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers is empty");
assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
assert_throws("NotFoundError",
function() { mediaSource.removeSourceBuffer(sourceBuffer); },
"removeSourceBuffer() throws an exception when closed.");
test.done();
}));
// Trigger the MediaSource to close.
mediaElement.src = "";
}, "Test removeSourceBuffer() while closed.");
test(function ()
{
var mediaSource = new MediaSource();
assert_throws("InvalidStateError",
function() { mediaSource.endOfStream(); },
"endOfStream() throws an exception when closed.");
}, "Test endOfStream() while closed.");
test(function ()
{
var mediaSource = new MediaSource();
assert_throws("InvalidStateError",
function() { mediaSource.endOfStream("decode"); },
"endOfStream(decode) throws an exception when closed.");
}, "Test endOfStream(decode) while closed.");
test(function ()
{
var mediaSource = new MediaSource();
assert_throws("InvalidStateError",
function() { mediaSource.endOfStream("network"); },
"endOfStream(network) throws an exception when closed.");
}, "Test endOfStream(network) while closed.");
test(function ()
{
var mediaSource = new MediaSource();
assert_throws("InvalidStateError",
function() { mediaSource.duration = 10; },
"Setting duration throws an exception when closed.");
}, "Test setting duration while closed.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
assert_equals(mediaSource.readyState, "open", "readyState is 'open'");
// Setup a handler to run when the MediaSource closes.
mediaSource.addEventListener("sourceclose", test.step_func(function (event)
{
assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
assert_throws("InvalidStateError",
function() { mediaSource.duration = 10; },
"Setting duration when closed throws an exception");
test.done();
}));
// Trigger the MediaSource to close.
mediaElement.src = "";
}, "Test setting duration while open->closed.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
assert_equals(mediaSource.readyState, "open", "readyState is 'open'");
// Setup a handler to run when the MediaSource closes.
mediaSource.addEventListener("sourceclose", test.step_func(function (event)
{
assert_equals(mediaSource.readyState, "closed", "readyState is 'closed'");
assert_true(isNaN(mediaSource.duration), "duration is NaN");
test.done();
}));
// Trigger the MediaSource to close.
mediaElement.src = "";
}, "Test getting duration while open->closed.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
assert_equals(mediaSource.readyState, "open", "readyState is open");
// Setup a handler to run when the MediaSource closes.
mediaSource.addEventListener("sourceclose", test.step_func(function (event)
{
assert_equals(mediaSource.readyState, "closed", "readyState is closed");
assert_throws("InvalidStateError",
function() { sourceBuffer.abort(); },
"sourceBuffer.abort() throws INVALID_STATE_ERROR");
test.done();
}));
// Trigger the MediaSource to close.
mediaElement.src = "";
}, "Test sourcebuffer.abort when closed.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>MP4 audio-only bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("mp4", "a-128k-44100Hz-1ch", "a-192k-44100Hz-1ch", "Tests mp4 audio-only bitrate changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>MP4 muxed audio &amp; video with an audio bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("mp4", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-448k-44100Hz-1ch-640x480-30fps-10kfr", "Tests mp4 audio bitrate changes in multiplexed content.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>MP4 muxed audio &amp; video with a video frame size change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("mp4", "av-384k-44100Hz-1ch-320x240-30fps-10kfr", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "Tests mp4 frame size changes in multiplexed content.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>MP4 muxed audio &amp; video with a video bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("mp4", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-640k-44100Hz-1ch-640x480-30fps-10kfr", "Tests mp4 video bitrate changes in multiplexed content.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>MP4 video-only bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("mp4", "v-128k-320x240-30fps-10kfr", "v-256k-320x240-30fps-10kfr", "Tests mp4 video-only bitrate changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>MP4 video-only frame rate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("mp4", "v-128k-320x240-24fps-8kfr", "v-128k-320x240-30fps-10kfr", "Tests mp4 video-only frame rate changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>MP4 video-only frame size change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("mp4", "v-128k-320x240-30fps-10kfr", "v-128k-640x480-30fps-10kfr", "Tests mp4 video-only frame size changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>WebM audio-only bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("webm", "a-128k-44100Hz-1ch", "a-192k-44100Hz-1ch", "Tests webm audio-only bitrate changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>WebM muxed audio &amp; video with an audio bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("webm", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-448k-44100Hz-1ch-640x480-30fps-10kfr", "Tests webm audio bitrate changes in multiplexed content.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>WebM muxed audio &amp; video with a video frame size change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("webm", "av-384k-44100Hz-1ch-320x240-30fps-10kfr", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "Tests webm frame size changes in multiplexed content.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>WebM muxed audio &amp; video with a video bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("webm", "av-384k-44100Hz-1ch-640x480-30fps-10kfr", "av-640k-44100Hz-1ch-640x480-30fps-10kfr", "Tests webm video bitrate changes in multiplexed content.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>WebM video-only bitrate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("webm", "v-128k-320x240-30fps-10kfr", "v-256k-320x240-30fps-10kfr", "Tests webm video-only bitrate changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>WebM video-only frame rate change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("webm", "v-128k-320x240-24fps-8kfr", "v-128k-320x240-30fps-10kfr", "Tests webm video-only frame rate changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>WebM video-only frame size change.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
<script src="mediasource-config-changes.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediaSourceConfigChangeTest("webm", "v-128k-320x240-30fps-10kfr", "v-128k-640x480-30fps-10kfr", "Tests webm video-only frame size changes.");
</script>
</body>
</html>

View file

@ -0,0 +1,101 @@
// Extract & return the resolution string from a filename, if any.
function resolutionFromFilename(filename)
{
resolution = filename.replace(/^.*[^0-9]([0-9]+x[0-9]+)[^0-9].*$/, "$1");
if (resolution != filename) {
return resolution;
}
return "";
}
function appendBuffer(test, sourceBuffer, data)
{
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.appendBuffer(data);
}
function mediaSourceConfigChangeTest(directory, idA, idB, description)
{
var manifestFilenameA = directory + "/test-" + idA + "-manifest.json";
var manifestFilenameB = directory + "/test-" + idB + "-manifest.json";
mediasource_test(function(test, mediaElement, mediaSource)
{
mediaElement.pause();
test.failOnEvent(mediaElement, 'error');
var expectResizeEvents = resolutionFromFilename(manifestFilenameA) != resolutionFromFilename(manifestFilenameB);
var expectedResizeEventCount = 0;
MediaSourceUtil.fetchManifestAndData(test, manifestFilenameA, function(typeA, dataA)
{
MediaSourceUtil.fetchManifestAndData(test, manifestFilenameB, function(typeB, dataB)
{
assert_equals(typeA, typeB, "Media format types match");
var sourceBuffer = mediaSource.addSourceBuffer(typeA);
appendBuffer(test, sourceBuffer, dataA);
++expectedResizeEventCount;
test.waitForExpectedEvents(function()
{
// Add the second buffer starting at 0.5 second.
sourceBuffer.timestampOffset = 0.5;
appendBuffer(test, sourceBuffer, dataB);
++expectedResizeEventCount;
});
test.waitForExpectedEvents(function()
{
// Add the first buffer starting at 1 second.
sourceBuffer.timestampOffset = 1;
appendBuffer(test, sourceBuffer, dataA);
++expectedResizeEventCount;
});
test.waitForExpectedEvents(function()
{
// Add the second buffer starting at 1.5 second.
sourceBuffer.timestampOffset = 1.5;
appendBuffer(test, sourceBuffer, dataB);
++expectedResizeEventCount;
});
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating");
assert_greater_than(mediaSource.duration, 2, "duration");
// Truncate the presentation to a duration of 2 seconds.
mediaSource.duration = 2;
assert_true(sourceBuffer.updating, "updating");
test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
});
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating");
mediaSource.endOfStream();
assert_false(sourceBuffer.updating, "updating");
if (expectResizeEvents) {
for (var i = 0; i < expectedResizeEventCount; ++i) {
test.expectEvent(mediaElement, "resize");
}
}
test.expectEvent(mediaElement, "ended");
mediaElement.play();
});
test.waitForExpectedEvents(function() {
test.done();
});
});
});
}, description, { timeout: 10000 } );
};

View file

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<title>MediaSource.duration boundary condition test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function DurationBoundaryConditionTest(testDurationValue, expectedError, description)
{
return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
// Append initialization segment.
test.expectEvent(sourceBuffer, "updateend", "sourceBuffer");
test.expectEvent(mediaElement, "loadedmetadata", "mediaElement");
sourceBuffer.appendBuffer(MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init));
test.waitForExpectedEvents(function()
{
if (expectedError) {
assert_throws(expectedError,
function() { mediaSource.duration = testDurationValue; },
"mediaSource.duration assignment throws an exception for " + testDurationValue);
test.done();
return;
}
mediaSource.duration = testDurationValue;
assert_equals(mediaSource.duration, testDurationValue, "mediaSource.duration");
assert_equals(mediaElement.duration, testDurationValue, "mediaElement.duration");
test.expectEvent(mediaElement, "durationchange", "mediaElement");
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.duration, testDurationValue, "mediaSource.duration");
assert_equals(mediaElement.duration, testDurationValue, "mediaElement.duration");
test.done();
});
});
}, description);
}
DurationBoundaryConditionTest(Math.pow(2, 31) - 1, null, "Set duration to 2^31 - 1");
DurationBoundaryConditionTest(1, null, "Set duration to 1");
DurationBoundaryConditionTest(Number.MAX_VALUE, null, "Set duration to Number.MAX_VALUE");
DurationBoundaryConditionTest(Number.MIN_VALUE, null, "Set duration to Number.MIN_VALUE");
DurationBoundaryConditionTest(Number.MAX_VALUE - 1, null, "Set duration to Number.MAX_VALUE - 1");
DurationBoundaryConditionTest(Number.MIN_VALUE - 1, "InvalidAccessError", "Set duration to Number.MIN_VALUE - 1");
DurationBoundaryConditionTest(Number.POSITIVE_INFINITY, null, "Set duration to Number.POSITIVE_INFINITY");
DurationBoundaryConditionTest(Number.NEGATIVE_INFINITY, "InvalidAccessError", "Set duration to Number.NEGATIVE_INFINITY");
DurationBoundaryConditionTest(-1 * Number.MAX_VALUE, "InvalidAccessError", "Set duration to lowest value.");
DurationBoundaryConditionTest(-101.9, "InvalidAccessError", "Set duration to a negative double.");
DurationBoundaryConditionTest(101.9, null, "Set duration to a positive double.");
DurationBoundaryConditionTest(0, null, "Set duration to zero");
DurationBoundaryConditionTest(NaN, "InvalidAccessError", "Set duration to NaN");
</script>
</body>
</html>

View file

@ -0,0 +1,217 @@
<!DOCTYPE html>
<html>
<head>
<title>MediaSource.duration &amp; HTMLMediaElement.duration test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function mediasource_truncated_duration_seek_test(testFunction, description, options)
{
return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
var fullDuration = segmentInfo.duration;
var seekTo = fullDuration / 2.0;
var truncatedDuration = seekTo / 2.0;
mediaElement.play();
// Append all the segments
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'playing', 'Playing triggered');
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.duration, fullDuration, 'mediaElement fullDuration');
assert_equals(mediaSource.duration, fullDuration, 'mediaSource fullDuration');
test.expectEvent(mediaElement, 'seeking', 'seeking to seekTo');
test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while seeking to seekTo');
test.expectEvent(mediaElement, 'seeked', 'seeked to seekTo');
mediaElement.currentTime = seekTo;
assert_true(mediaElement.seeking, 'mediaElement.seeking (to seekTo)');
});
test.waitForExpectedEvents(function()
{
assert_greater_than_equal(mediaElement.currentTime, seekTo, 'Playback time has reached seekTo');
assert_equals(mediaElement.duration, fullDuration, 'mediaElement fullDuration after seekTo');
assert_equals(mediaSource.duration, fullDuration, 'mediaSource fullDuration after seekTo');
assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to seekTo');
test.expectEvent(mediaElement, 'seeking', 'Seeking to truncated duration');
assert_false(sourceBuffer.updating, 'sourceBuffer.updating');
mediaSource.duration = truncatedDuration;
assert_true(sourceBuffer.updating, 'sourceBuffer.updating');
test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
assert_true(mediaElement.seeking, 'Seeking after setting truncatedDuration');
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.currentTime, truncatedDuration,
'Playback time is truncatedDuration while seeking');
assert_true(mediaElement.seeking, 'mediaElement.seeking while seeking to truncatedDuration');
assert_equals(mediaElement.duration, truncatedDuration,
'mediaElement truncatedDuration during seek to it');
assert_equals(mediaSource.duration, truncatedDuration,
'mediaSource truncatedDuration during seek to it');
testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData,
truncatedDuration);
});
}, description, options);
}
mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
mediaData, truncatedDuration)
{
// Tests that duration truncation below current playback position
// starts seek to new duration.
test.done();
}, 'Test seek starts on duration truncation below currentTime');
mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
mediaData, truncatedDuration)
{
// The duration has been truncated at this point, and there is an
// outstanding seek pending.
test.expectEvent(sourceBuffer, 'updateend', 'updateend after appending more data');
test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
// Allow seek to complete by appending more data beginning at the
// truncated duration timestamp.
sourceBuffer.timestampOffset = truncatedDuration;
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
assert_greater_than_equal(mediaElement.currentTime, truncatedDuration,
'Playback time has reached truncatedDuration');
assert_approx_equals(mediaElement.duration, truncatedDuration + segmentInfo.duration, 0.05,
'mediaElement duration increased by new append');
assert_equals(mediaSource.duration, mediaElement.duration,
'mediaSource duration increased by new append');
assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
test.done();
});
}, 'Test appendBuffer completes previous seek to truncated duration');
mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
mediaData, truncatedDuration)
{
// The duration has been truncated at this point, and there is an
// outstanding seek pending.
test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
// Call endOfStream() to complete the pending seek.
mediaSource.endOfStream();
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.currentTime, truncatedDuration,
'Playback time has reached truncatedDuration');
assert_equals(mediaElement.duration, truncatedDuration,
'mediaElement truncatedDuration after seek to it');
assert_equals(mediaSource.duration, truncatedDuration,
'mediaSource truncatedDuration after seek to it');
assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
test.done();
});
}, 'Test endOfStream completes previous seek to truncated duration');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
var fullDuration = segmentInfo.duration;
var newDuration = 0.5;
var expectedDurationChangeEventCount = 1;
var durationchangeEventCounter = 0;
var durationchangeEventHandler = test.step_func(function(event)
{
assert_equals(mediaElement.duration, newDuration, 'mediaElement newDuration');
assert_equals(mediaSource.duration, newDuration, 'mediaSource newDuration');
durationchangeEventCounter++;
});
mediaElement.play();
// Append all the segments
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'playing', 'Playing triggered');
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.duration, fullDuration, 'mediaElement fullDuration');
assert_equals(mediaSource.duration, fullDuration, 'mediaSource fullDuration');
assert_less_than(mediaElement.currentTime, newDuration / 2, 'mediaElement currentTime');
// Media load also fires 'durationchange' event, so only start counting them now.
mediaElement.addEventListener('durationchange', durationchangeEventHandler);
assert_false(sourceBuffer.updating, "updating");
// Truncate duration. This should result in one 'durationchange' fired.
mediaSource.duration = newDuration;
assert_true(sourceBuffer.updating, "updating");
test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
});
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating");
// Set duration again to make sure it does not trigger another 'durationchange' event.
mediaSource.duration = newDuration;
// Mark endOfStream so that playback can reach 'ended' at the new duration.
test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
mediaSource.endOfStream();
// endOfStream can change duration downwards slightly.
// Allow for one more 'durationchange' event only in this case.
var currentDuration = mediaSource.duration;
if (currentDuration != newDuration) {
assert_true(currentDuration > 0 && currentDuration < newDuration, 'adjusted duration');
newDuration = currentDuration;
++expectedDurationChangeEventCount;
}
// Allow media to play to end while counting 'durationchange' events.
test.expectEvent(mediaElement, 'ended', 'Playback ended');
test.waitForExpectedEvents(function()
{
mediaElement.removeEventListener('durationchange', durationchangeEventHandler);
assert_equals(durationchangeEventCounter, expectedDurationChangeEventCount, 'durationchanges');
test.done();
});
});
}, 'Test setting same duration multiple times does not fire duplicate durationchange', {timeout: 2500});
</script>
</body>
</html>

View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<title>Invalid MediaSource.endOfStream() parameter test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_test(function(test, mediaElement, mediaSource)
{
test.failOnEvent(mediaElement, 'error');
assert_equals(mediaSource.readyState, 'open');
assert_throws(new TypeError(),
function() { mediaSource.endOfStream('garbage'); },
'endOfStream(\'garbage\') throws TypeError');
assert_equals(mediaSource.readyState, 'open');
test.done();
}, 'Test MediaSource.endOfStream() with invalid non-empty error string.');
mediasource_test(function(test, mediaElement, mediaSource)
{
test.failOnEvent(mediaElement, 'error');
assert_equals(mediaSource.readyState, 'open');
assert_throws(new TypeError(),
function() { mediaSource.endOfStream(''); },
'endOfStream(\'\') throws TypeError');
assert_equals(mediaSource.readyState, 'open');
test.done();
}, 'Test MediaSource.endOfStream() with invalid empty error string.');
mediasource_test(function(test, mediaElement, mediaSource)
{
test.failOnEvent(mediaElement, 'error');
assert_equals(mediaSource.readyState, 'open');
assert_throws(new TypeError(),
function() { mediaSource.endOfStream(null); },
'endOfStream(null) throws TypeError');
assert_equals(mediaSource.readyState, 'open');
test.done();
}, 'Test MediaSource.endOfStream() with invalid null error parameter.');
</script>
</body>
</html>

View file

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<head>
<title>HTMLVideoElement.getVideoPlaybackQuality() test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var previousQuality = mediaElement.getVideoPlaybackQuality();
var timeUpdateCount = 0;
mediaElement.addEventListener("timeupdate", test.step_func(function (e)
{
var videoElement = e.target;
var newQuality = videoElement.getVideoPlaybackQuality();
assert_not_equals(previousQuality, newQuality, "Verify new object");
assert_greater_than(newQuality.creationTime, previousQuality.creationTime, "creationTime");
assert_greater_than_equal(newQuality.totalVideoFrames, 0, "totalVideoFrames >= 0");
assert_greater_than_equal(newQuality.totalVideoFrames, previousQuality.totalVideoFrames, "totalVideoFrames");
assert_greater_than_equal(newQuality.droppedVideoFrames, 0, "droppedVideoFrames >= 0");
assert_greater_than_equal(newQuality.droppedVideoFrames, previousQuality.droppedVideoFrames, "droppedVideoFrames");
assert_greater_than_equal(newQuality.corruptedVideoFrames, 0, "corruptedVideoFrames >= 0");
assert_greater_than_equal(newQuality.corruptedVideoFrames, previousQuality.corruptedVideoFrames, "corruptedVideoFrames");
previousQuality = newQuality;
timeUpdateCount++;
}));
test.failOnEvent(mediaElement, 'error');
test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating");
assert_greater_than(mediaSource.duration, 1, "duration");
mediaSource.duration = 1;
assert_true(sourceBuffer.updating, "updating");
test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
});
test.waitForExpectedEvents(function()
{
mediaSource.endOfStream();
mediaElement.play();
test.expectEvent(mediaElement, 'ended', 'mediaElement');
});
test.waitForExpectedEvents(function()
{
assert_greater_than(timeUpdateCount, 2, "timeUpdateCount");
test.done();
});
}, "Test HTMLVideoElement.getVideoPlaybackQuality() with MediaSource API", {timeout: 5000});
</script>
</body>
</html>

View file

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<title>MediaSource.isTypeSupported() test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
// Generate a distinct test for each type in types
function test_type_support(types, expectation, description)
{
for (var i = 0; i < types.length; ++i) {
test(function()
{
assert_equals(MediaSource.isTypeSupported(types[i]),
expectation, 'supported');
}, description + ' "' + types[i] + '"');
}
};
test_type_support([
'video',
'video/',
'video/webm',
'video/webm;',
'video/webm;codecs',
'video/webm;codecs=',
'video/webm;codecs="',
'video/webm;codecs=""',
'video/webm;codecs=","',
'',
null
], false, 'Test invalid MIME format');
test_type_support([
'audio/webm;codecs="vp8"',
'audio/mp4;codecs="avc1.4d001e"',
], false, 'Test invalid mismatch between major type and codec ID');
test_type_support([
'audio/mp4;codecs="vorbis"',
'audio/webm;codecs="mp4a.40.2"',
'video/mp4;codecs="vp8"',
'video/webm;codecs="mp4a.40.2"',
'video/mp4;codecs="vorbis"',
'video/webm;codecs="mp4a.40.2"',
], false, 'Test invalid mismatch between minor type and codec ID');
test_type_support([
'audio/mp4;codecs="mp4a"',
'audio/mp4;codecs="mp4a.40"',
'audio/mp4;codecs="mp4a.40."',
'audio/mp4;codecs="mp4a.67.3"'
], false, 'Test invalid codec ID');
test_type_support([
'video/webm;codecs="vp8"',
'video/webm;codecs="vorbis"',
'video/webm;codecs="vp8,vorbis"',
'video/webm;codecs="vorbis, vp8"',
'audio/webm;codecs="vorbis"',
'AUDIO/WEBM;CODECS="vorbis"',
], true, 'Test valid WebM type');
test_type_support([
'video/mp4;codecs="avc1.4d001e"', // H.264 Main Profile level 3.0
'video/mp4;codecs="avc1.42001e"', // H.264 Baseline Profile level 3.0
'audio/mp4;codecs="mp4a.40.2"', // MPEG4 AAC-LC
'audio/mp4;codecs="mp4a.40.5"', // MPEG4 HE-AAC
'audio/mp4;codecs="mp4a.67"', // MPEG2 AAC-LC
'video/mp4;codecs="mp4a.40.2"',
'video/mp4;codecs="avc1.4d001e,mp4a.40.2"',
'video/mp4;codecs="mp4a.40.2 , avc1.4d001e "',
'video/mp4;codecs="avc1.4d001e,mp4a.40.5"',
], true, 'Test valid MP4 type');
</script>
</body>
</html>

View file

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html>
<head>
<title>Test Attaching a MediaSource to multiple HTMLMediaElements.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function twoMediaElementTest(testFunction, description)
{
media_test(function(test)
{
var firstMediaTag = document.createElement('video');
var secondMediaTag = document.createElement('video');
document.body.appendChild(firstMediaTag);
document.body.appendChild(secondMediaTag);
// Overload done() so that elements added to the document can be
// removed.
var removeMediaElements = true;
var oldTestDone = test.done.bind(test);
test.done = function()
{
if (removeMediaElements) {
document.body.removeChild(secondMediaTag);
document.body.removeChild(firstMediaTag);
removeMediaElements = false;
}
oldTestDone();
};
testFunction(test, firstMediaTag, secondMediaTag);
}, description);
}
twoMediaElementTest(function(test, firstMediaTag, secondMediaTag)
{
// When attachment of mediaSource to two MediaElements is done
// without an intervening stable state, exactly one of the two
// MediaElements should successfully attach, and the other one
// should get error event due to mediaSource already in 'open'
// readyState.
var mediaSource = new MediaSource();
var mediaSourceURL = URL.createObjectURL(mediaSource);
var gotSourceOpen = false;
var gotError = false;
var doneIfFinished = test.step_func(function()
{
if (gotSourceOpen && gotError)
test.done();
});
var errorHandler = test.step_func(function(e)
{
firstMediaTag.removeEventListener('error', errorHandler);
secondMediaTag.removeEventListener('error', errorHandler);
var eventTarget = e.target;
var otherTarget;
if (eventTarget == firstMediaTag) {
otherTarget = secondMediaTag;
} else {
assert_equals(eventTarget, secondMediaTag, 'Error target check');
otherTarget = firstMediaTag;
}
assert_true(eventTarget.error != null, 'Error state on one tag');
assert_equals(eventTarget.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, 'Expected error code');
assert_equals(otherTarget.error, null, 'No error on other tag');
assert_equals(eventTarget.networkState, HTMLMediaElement.NETWORK_NO_SOURCE,
'Tag with error state networkState');
assert_equals(otherTarget.networkState, HTMLMediaElement.NETWORK_LOADING,
'Tag without error state networkState');
gotError = true;
doneIfFinished();
});
test.expectEvent(mediaSource, 'sourceopen', 'An attachment succeeded');
firstMediaTag.addEventListener('error', errorHandler);
secondMediaTag.addEventListener('error', errorHandler);
firstMediaTag.src = mediaSourceURL;
secondMediaTag.src = mediaSourceURL;
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, 'open', 'Source is opened');
gotSourceOpen = true;
doneIfFinished();
});
}, 'Test exactly one succeeds when two MediaElements attach to same MediaSource');
mediasource_test(function(test, mediaElement, mediaSource) {
assert_equals(mediaSource.readyState, 'open', 'Source open');
// Set the tag's src attribute. This should close mediaSource,
// reattach it to the tag, and initiate source reopening.
test.expectEvent(mediaSource, 'sourceopen', 'Source attached again');
mediaElement.src = URL.createObjectURL(mediaSource);
assert_equals(mediaSource.readyState, 'closed', 'Source closed');
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, 'open', 'Source reopened');
test.done();
});
}, 'Test that MediaSource can reattach if closed first');
</script>
</body>
</html>

View file

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<title>Simple MediaSource playback &amp; seek test case.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaElement.play();
// Append all the segments
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'playing', 'Playing triggered');
sourceBuffer.appendBuffer(mediaData);
function confirmPlayThenEnd()
{
test.waitForCurrentTimeChange(mediaElement, function ()
{
assert_greater_than(mediaElement.currentTime, 0.0, 'Playback has started after seek.');
test.done();
});
}
function finishSeekThenPlay()
{
assert_true(mediaElement.seeking, 'mediaElement is seeking');
assert_equals(mediaElement.currentTime, 0.0, 'Current time is 0.0');
test.expectEvent(mediaElement, 'seeked', 'mediaElement finished seek');
test.waitForExpectedEvents(confirmPlayThenEnd);
}
function delayedPlayHandler()
{
assert_greater_than(mediaElement.currentTime, 0.0, 'Playback has started.');
test.expectEvent(mediaElement, 'seeking', 'mediaElement');
mediaElement.currentTime = 0.0;
test.waitForExpectedEvents(finishSeekThenPlay);
}
test.waitForExpectedEvents(function()
{
test.waitForCurrentTimeChange(mediaElement, delayedPlayHandler);
});
}, 'Test playing then seeking back.');
</script>
</body>
</html>

View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<title>Simple MediaSource playback test case.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.failOnEvent(mediaElement, 'error');
test.endOnEvent(mediaElement, 'ended');
test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating");
assert_greater_than(mediaSource.duration, 1, "duration");
mediaSource.duration = 1;
assert_true(sourceBuffer.updating, "updating");
test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
});
test.waitForExpectedEvents(function()
{
mediaSource.endOfStream();
mediaElement.play();
});
}, "Test normal playback case with MediaSource API", {timeout: 5000});
</script>
</body>
</html>

View file

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<title>Test MediaSource behavior when receiving multiple seek requests during a pending seek.</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaElement.play();
// Append all media data for complete playback.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer end update.');
test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
test.expectEvent(mediaElement, 'playing', 'Playing media.');
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
var bufferedRanges = mediaElement.buffered;
assert_greater_than_equal(mediaElement.duration, 4.0, 'Duration is >= 4.0s');
assert_equals(bufferedRanges.length, 1, 'Just one buffered range');
assert_less_than_equal(bufferedRanges.start(0), 1.0, 'Buffered range starts <= 1.0s');
assert_greater_than_equal(bufferedRanges.end(0), 4.0, 'Buffered range ends >= 4.0s');
test.expectEvent(mediaElement, 'seeking', 'seeking');
test.expectEvent(mediaElement, 'timeupdate', 'timeupdate');
test.expectEvent(mediaElement, 'seeked', 'seeked');
// Request seeks.
mediaElement.currentTime = 1.0;
// This 'ephemeral' seek should be invisible to javascript, except any latency incurred in its processing.
mediaElement.currentTime = 3.0;
mediaElement.currentTime = 1.0;
assert_true(mediaElement.seeking, 'Element is seeking');
assert_equals(mediaElement.currentTime, 1.0, 'Element time is at last seek time');
});
test.waitForExpectedEvents(function()
{
// No more seeking or seeked events should occur.
test.failOnEvent(mediaElement, 'seeking');
test.failOnEvent(mediaElement, 'seeked');
assert_false(mediaElement.seeking, 'Element is not seeking');
assert_greater_than_equal(mediaElement.currentTime, 1.0, 'Element time is at or after last seek time');
assert_less_than(mediaElement.currentTime, 3.0, 'Element time is before the ephemeral seek time');
var timeBeforeWait = mediaElement.currentTime;
test.waitForCurrentTimeChange(mediaElement, function()
{
// Time should have advanced a little, but not yet reached the ephemeral seek time.
assert_greater_than(mediaElement.currentTime, timeBeforeWait, 'Element time has increased');
assert_less_than(mediaElement.currentTime, 3.0, 'Element time is still before the ephemeral seek time');
test.done();
});
});
}, 'Test redundant fully prebuffered seek');
</script>
</body>
</html>

View file

@ -0,0 +1,293 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBuffer.remove() test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_throws("InvalidAccessError", function()
{
sourceBuffer.remove(-1, 2);
}, "remove");
test.done();
}, "Test remove with an negative start.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
[ undefined, NaN, Infinity, -Infinity ].forEach(function(item)
{
assert_throws(new TypeError(), function()
{
sourceBuffer.remove(item, 2);
}, "remove");
});
test.done();
}, "Test remove with non-finite start.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
mediaSource.duration = 10;
assert_throws("InvalidAccessError", function()
{
sourceBuffer.remove(11, 12);
}, "remove");
test.done();
}, "Test remove with a start beyond the duration.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
mediaSource.duration = 10;
assert_throws("InvalidAccessError", function()
{
sourceBuffer.remove(2, 1);
}, "remove");
test.done();
}, "Test remove with a start larger than the end.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_throws("InvalidAccessError", function()
{
sourceBuffer.remove(0, Number.NEGATIVE_INFINITY);
}, "remove");
test.done();
}, "Test remove with a NEGATIVE_INFINITY end.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_throws("InvalidAccessError", function()
{
sourceBuffer.remove(0, Number.NaN);
}, "remove");
test.done();
}, "Test remove with a NaN end.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
mediaSource.duration = 10;
mediaSource.removeSourceBuffer(sourceBuffer);
assert_throws("InvalidStateError", function()
{
sourceBuffer.remove(1, 2);
}, "remove");
test.done();
}, "Test remove after SourceBuffer removed from mediaSource.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
mediaSource.duration = 10;
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.remove(1, 2);
assert_true(sourceBuffer.updating, "updating");
assert_throws("InvalidStateError", function()
{
sourceBuffer.remove(3, 4);
}, "remove");
test.waitForExpectedEvents(function()
{
test.done();
});
}, "Test remove while update pending.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
mediaSource.duration = 10;
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "abort");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.remove(1, 2);
assert_true(sourceBuffer.updating, "updating");
sourceBuffer.abort();
assert_false(sourceBuffer.updating, "updating");
test.waitForExpectedEvents(function()
{
test.done();
});
}, "Test aborting a remove operation.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
sourceBuffer.appendBuffer(mediaData);
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
test.waitForExpectedEvents(function()
{
assert_less_than(mediaSource.duration, 10)
mediaSource.duration = 10;
sourceBuffer.remove(mediaSource.duration, mediaSource.duration + 2);
assert_true(sourceBuffer.updating, "updating");
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
});
test.waitForExpectedEvents(function()
{
test.done();
});
}, "Test remove with a start at the duration.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
mediaSource.endOfStream();
assert_equals(mediaSource.readyState, "ended");
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.remove(1, 2);
assert_true(sourceBuffer.updating, "updating");
assert_equals(mediaSource.readyState, "open");
});
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating");
test.done();
});
}, "Test remove transitioning readyState from 'ended' to 'open'.");
function removeAppendedDataTests(callback, description)
{
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
mediaSource.endOfStream();
assert_false(sourceBuffer.updating, "updating");
var duration = mediaElement.duration.toFixed(3);
var subType = MediaSourceUtil.getSubType(segmentInfo.type);
assertBufferedEquals(sourceBuffer, "{ [0.000, " + duration + ") }", "Initial buffered range.");
callback(test, mediaSource, sourceBuffer, duration, subType);
});
}, description);
};
function removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, start, end, expected)
{
test.expectEvent(sourceBuffer, "updatestart");
test.expectEvent(sourceBuffer, "update");
test.expectEvent(sourceBuffer, "updateend");
sourceBuffer.remove(start, end);
test.waitForExpectedEvents(function()
{
mediaSource.endOfStream();
assert_false(sourceBuffer.updating, "updating");
assertBufferedEquals(sourceBuffer, expected, "Buffered ranges after remove().");
test.done();
});
}
removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
{
removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 0, Number.POSITIVE_INFINITY, "{ }");
}, "Test removing all appended data.");
removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
{
var expectations = {
webm: ("{ [3.187, " + duration + ") }"),
mp4: ("{ [3.154, " + duration + ") }"),
};
// Note: Range doesn't start exactly at the end of the remove range because there isn't
// a keyframe there. The resulting range starts at the first keyframe >= the end time.
removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 0, 3, expectations[subType]);
}, "Test removing beginning of appended data.");
removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
{
var expectations = {
webm: ("{ [0.000, 1.012) [3.187, " + duration + ") }"),
mp4: ("{ [0.000, 1.022) [3.154, " + duration + ") }"),
};
// Note: The first resulting range ends slightly after start because the removal algorithm only removes
// frames with a timestamp >= the start time. If a frame starts before and ends after the remove() start
// timestamp, then it stays in the buffer.
removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 1, 3, expectations[subType]);
}, "Test removing the middle of appended data.");
removeAppendedDataTests(function(test, mediaSource, sourceBuffer, duration, subType)
{
var expectations = {
webm: "{ [0.000, 1.012) }",
mp4: "{ [0.000, 1.029) }",
};
removeAndCheckBufferedRanges(test, mediaSource, sourceBuffer, 1, Number.POSITIVE_INFINITY, expectations[subType]);
}, "Test removing the end of appended data.");
</script>
</body>
</html>

View file

@ -0,0 +1,92 @@
<!DOCTYPE html>
<html>
<head>
<title>MediaSource.removeSourceBuffer() test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
mediaSource.removeSourceBuffer(sourceBuffer);
var sourceBuffer2 = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer2 != null, "New SourceBuffer returned");
assert_true(sourceBuffer != sourceBuffer2, "SourceBuffers are different instances.");
assert_equals(mediaSource.sourceBuffers.length, 1, "sourceBuffers.length == 1");
test.done();
}, "Test addSourceBuffer(), removeSourceBuffer(), addSourceBuffer() sequence.");
mediasource_test(function(test, mediaElement, mediaSource)
{
assert_throws(new TypeError(),
function() { mediaSource.removeSourceBuffer(null); },
"removeSourceBuffer() threw an exception when passed null.");
test.done();
}, "Test removeSourceBuffer() with null");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
mediaSource.removeSourceBuffer(sourceBuffer);
assert_throws("NotFoundError",
function() { mediaSource.removeSourceBuffer(sourceBuffer); },
"removeSourceBuffer() threw an exception when a SourceBuffer that was already removed.");
test.done();
}, "Test calling removeSourceBuffer() twice with the same object.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
mediaSource.endOfStream();
assert_true(mediaSource.readyState == "ended", "MediaSource in ended state");
mediaSource.removeSourceBuffer(sourceBuffer);
assert_true(mediaSource.sourceBuffers.length == 0, "MediaSource.sourceBuffers is empty");
assert_true(mediaSource.activeSourceBuffers.length == 0, "MediaSource.activesourceBuffers is empty");
test.done();
}, "Test calling removeSourceBuffer() in ended state.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata done.");
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assert_true(mediaSource.sourceBuffers.length == 1, "MediaSource.sourceBuffers is not empty");
assert_true(mediaSource.activeSourceBuffers.length == 1, "MediaSource.activesourceBuffers is not empty");
assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA);
assert_equals(mediaSource.duration, segmentInfo.duration);
test.expectEvent(mediaSource.activeSourceBuffers, "removesourcebuffer", "SourceBuffer removed from activeSourceBuffers.");
test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "SourceBuffer removed.");
mediaSource.removeSourceBuffer(sourceBuffer);
});
test.waitForExpectedEvents(function()
{
assert_true(mediaSource.sourceBuffers.length == 0, "MediaSource.sourceBuffers is empty");
assert_true(mediaSource.activeSourceBuffers.length == 0, "MediaSource.activesourceBuffers is empty");
test.done();
});
}, "Test removesourcebuffer event on activeSourceBuffers.");
</script>
</body>
</html>

View file

@ -0,0 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<title>Test MediaSource behavior when seeking beyond the duration of the clip.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function seekToSpecifiedTimeSetEOSAndVerifyDone(test, mediaElement, mediaSource, seekToTime)
{
assert_less_than(mediaElement.currentTime, mediaElement.duration, 'Not at the end yet.');
test.expectEvent(mediaElement, 'seeking', 'mediaElement seeking');
// Seek to specified time.
mediaElement.currentTime = seekToTime;
if (seekToTime >= mediaSource.duration) {
assert_equals(mediaElement.currentTime, mediaSource.duration, 'Current time equals duration.');
} else {
assert_equals(mediaElement.currentTime, seekToTime, 'Current time equals specified seek time.');
}
test.waitForExpectedEvents(function()
{
test.expectEvent(mediaElement, 'timeupdate', 'mediaElement time updated.');
test.expectEvent(mediaElement, 'seeked', 'mediaElement seeked');
test.expectEvent(mediaElement, 'ended', 'mediaElement ended.');
test.expectEvent(mediaSource, 'sourceended', 'mediaSource ended.');
mediaSource.endOfStream();
assert_true(mediaElement.seeking, 'mediaElement seeking.');
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.currentTime, mediaSource.duration, 'Current time equals duration.');
test.done();
});
};
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaElement.play();
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
// Append the initialization segment to trigger a transition to HAVE_METADATA.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer end update.');
test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
// Add sufficient segments to have at least 2s of play-time.
var playbackData = MediaSourceUtil.getMediaDataForPlaybackTime(mediaData, segmentInfo, 2.0);
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'playing', 'Playing media.');
sourceBuffer.appendBuffer(playbackData);
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaElement.duration, segmentInfo.duration);
assert_greater_than_equal(mediaElement.duration, 2.0, 'Duration is >2.0s.');
test.waitForCurrentTimeChange(mediaElement, function()
{
// Update duration.
mediaSource.duration = 1.5;
seekToSpecifiedTimeSetEOSAndVerifyDone(test, mediaElement, mediaSource, 1.8);
});
});
}, 'Test seeking beyond updated media duration.');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaElement.play();
// Append all media data for complete playback.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer end update.');
test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
test.expectEvent(mediaElement, 'playing', 'Playing media.');
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
test.waitForCurrentTimeChange(mediaElement, function()
{
seekToSpecifiedTimeSetEOSAndVerifyDone(test, mediaElement, mediaSource, mediaSource.duration, mediaSource.duration + 0.1);
});
});
}, 'Test seeking beyond media duration.');
</script>
</body>
</html>

View file

@ -0,0 +1,142 @@
<!DOCTYPE html>
<html>
<head>
<title>Test MediaSource behavior when a seek is requested while another seek is pending.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaElement.play();
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var firstSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
var segmentIndex = 2;
var secondSegmentInfo = segmentInfo.media[segmentIndex];
// Append the initialization segment to trigger a transition to HAVE_METADATA.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assert_false(mediaElement.seeking, 'mediaElement is not seeking');
assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA, 'Still in HAVE_METADATA');
// Seek to a new position before letting the initial seek to 0 completes.
test.expectEvent(mediaElement, 'seeking', 'mediaElement');
mediaElement.currentTime = secondSegmentInfo.timecode;
assert_true(mediaElement.seeking, 'mediaElement is seeking');
// Append media data for time 0.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
sourceBuffer.appendBuffer(firstSegment);
});
test.waitForExpectedEvents(function()
{
// Verify that the media data didn't trigger a 'seeking' event or a transition beyond HAVE_METADATA.
assert_true(mediaElement.seeking, 'mediaElement is still seeking');
assert_equals(mediaElement.readyState, mediaElement.HAVE_METADATA, 'Still in HAVE_METADATA');
// Append media data for the current position until the element starts playing.
test.expectEvent(mediaElement, 'seeked', 'mediaElement finished seek');
test.expectEvent(mediaElement, 'playing', 'mediaElement playing');
MediaSourceUtil.appendUntilEventFires(test, mediaElement, 'playing', sourceBuffer, mediaData, segmentInfo, segmentIndex);
});
test.waitForExpectedEvents(function()
{
test.expectEvent(mediaSource, 'sourceended', 'mediaSource ended');
mediaSource.endOfStream();
});
test.waitForExpectedEvents(function()
{
assert_greater_than(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA, 'Greater than HAVE_CURRENT_DATA');
test.done();
});
}, 'Test seeking to a new location before transitioning beyond HAVE_METADATA.', {timeout: 10000} );
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaElement.play();
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var firstSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
var secondSegmentInfo = segmentInfo.media[2];
var secondSegment = MediaSourceUtil.extractSegmentData(mediaData, secondSegmentInfo);
var segmentIndex = 4;
var thirdSegmentInfo = segmentInfo.media[segmentIndex];
// Append the initialization segment to trigger a transition to HAVE_METADATA.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'loadedmetadata', 'Reached HAVE_METADATA');
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'playing', 'mediaElement playing');
sourceBuffer.appendBuffer(firstSegment);
});
test.waitForExpectedEvents(function()
{
assert_greater_than(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA, 'Greater than HAVE_CURRENT_DATA');
// Seek to a new position.
test.expectEvent(mediaElement, 'seeking', 'mediaElement');
mediaElement.currentTime = secondSegmentInfo.timecode;
assert_true(mediaElement.seeking, 'mediaElement is seeking');
});
test.waitForExpectedEvents(function()
{
assert_true(mediaElement.seeking, 'mediaElement is still seeking');
// Seek to a second position while the first seek is still pending.
test.expectEvent(mediaElement, 'seeking', 'mediaElement');
mediaElement.currentTime = thirdSegmentInfo.timecode;
assert_true(mediaElement.seeking, 'mediaElement is seeking');
// Append media data for the first seek position.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
sourceBuffer.appendBuffer(secondSegment);
});
test.waitForExpectedEvents(function()
{
assert_true(mediaElement.seeking, 'mediaElement is still seeking');
// Append media data for the second seek position.
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.expectEvent(mediaElement, 'seeked', 'mediaElement finished seek');
MediaSourceUtil.appendUntilEventFires(test, mediaElement, 'seeked', sourceBuffer, mediaData, segmentInfo, segmentIndex);
});
test.waitForExpectedEvents(function()
{
assert_false(mediaElement.seeking, 'mediaElement is no longer seeking');
test.expectEvent(mediaSource, 'sourceended', 'mediaSource ended');
mediaSource.endOfStream();
});
test.waitForExpectedEvents(function()
{
assert_greater_than(mediaElement.readyState, mediaElement.HAVE_CURRENT_DATA, 'Greater than HAVE_CURRENT_DATA');
test.done();
});
}, 'Test seeking to a new location during a pending seek.', {timeout: 10000} );
</script>
</body>
</html>

View file

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBuffer.mode == "sequence" test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function mediasource_sequencemode_test(testFunction, description, options)
{
return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_greater_than(segmentInfo.media.length, 3, "at least 3 media segments for supported type");
test.failOnEvent(mediaElement, "error");
sourceBuffer.mode = "sequence";
assert_equals(sourceBuffer.mode, "sequence", "mode after setting it to \"sequence\"");
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
test.expectEvent(sourceBuffer, "updatestart", "initSegment append started.");
test.expectEvent(sourceBuffer, "update", "initSegment append success.");
test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assert_equals(sourceBuffer.timestampOffset, 0, "timestampOffset initially 0");
testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData);
});
}, description, options);
}
function append_segment(test, sourceBuffer, mediaData, info, callback)
{
var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, info);
test.expectEvent(sourceBuffer, "updatestart", "media segment append started.");
test.expectEvent(sourceBuffer, "update", "media segment append success.");
test.expectEvent(sourceBuffer, "updateend", "media segment append ended.");
sourceBuffer.appendBuffer(mediaSegment);
test.waitForExpectedEvents(callback);
}
function threeDecimalPlaces(number)
{
return Number(number.toFixed(3));
}
// Verifies expected times to 3 decimal places before and after mediaSource.endOfStream(),
// and calls |callback| on success.
function verify_offset_and_buffered(test, mediaSource, sourceBuffer,
expectedTimestampOffset, expectedBufferedRangeStartTime,
expectedBufferedRangeMaxEndTimeBeforeEOS,
expectedBufferedRangeEndTimeAfterEOS,
callback) {
assert_equals(threeDecimalPlaces(sourceBuffer.timestampOffset),
threeDecimalPlaces(expectedTimestampOffset),
"expectedTimestampOffset");
// Prior to EOS, the buffered range end time may not have fully reached the next media
// segment's timecode (adjusted by any timestampOffset). It should not exceed it though.
// Therefore, an exact assertBufferedEquals() will not work here.
assert_equals(sourceBuffer.buffered.length, 1, "sourceBuffer.buffered has 1 range before EOS");
assert_equals(threeDecimalPlaces(sourceBuffer.buffered.start(0)),
threeDecimalPlaces(expectedBufferedRangeStartTime),
"sourceBuffer.buffered range begins where expected before EOS");
assert_less_than_equal(threeDecimalPlaces(sourceBuffer.buffered.end(0)),
threeDecimalPlaces(expectedBufferedRangeMaxEndTimeBeforeEOS),
"sourceBuffer.buffered range ends at or before expected upper bound before EOS");
test.expectEvent(mediaSource, "sourceended", "mediaSource endOfStream");
mediaSource.endOfStream();
test.waitForExpectedEvents(function()
{
assertBufferedEquals(sourceBuffer,
"{ [" + expectedBufferedRangeStartTime.toFixed(3) + ", " + expectedBufferedRangeEndTimeAfterEOS.toFixed(3) + ") }",
"sourceBuffer.buffered after EOS");
callback();
});
}
mediasource_sequencemode_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_equals(segmentInfo.media[0].timecode, 0, "segment starts at time 0");
append_segment(test, sourceBuffer, mediaData, segmentInfo.media[0], function()
{
verify_offset_and_buffered(test, mediaSource, sourceBuffer,
0, 0,
segmentInfo.media[1].timecode + sourceBuffer.timestampOffset,
segmentInfo.media[0].highest_end_time + sourceBuffer.timestampOffset,
test.done);
});
}, "Test sequence AppendMode appendBuffer(first media segment)");
mediasource_sequencemode_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_greater_than(segmentInfo.media[1].timecode, 0, "segment starts after time 0");
append_segment(test, sourceBuffer, mediaData, segmentInfo.media[1], function()
{
verify_offset_and_buffered(test, mediaSource, sourceBuffer,
-segmentInfo.media[1].timecode, 0,
segmentInfo.media[2].timecode + sourceBuffer.timestampOffset,
segmentInfo.media[1].highest_end_time + sourceBuffer.timestampOffset,
test.done);
});
}, "Test sequence AppendMode appendBuffer(second media segment)");
mediasource_sequencemode_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_greater_than(segmentInfo.media[1].timecode, 0, "segment starts after time 0");
append_segment(test, sourceBuffer, mediaData, segmentInfo.media[1], function()
{
assert_equals(segmentInfo.media[0].timecode, 0, "segment starts at time 0");
append_segment(test, sourceBuffer, mediaData, segmentInfo.media[0], function()
{
// Current timestampOffset should reflect offset required to put media[0]
// immediately after media[1]'s highest frame end timestamp (as was adjusted
// by an earlier timestampOffset).
verify_offset_and_buffered(test, mediaSource, sourceBuffer,
segmentInfo.media[1].highest_end_time - segmentInfo.media[1].timecode, 0,
segmentInfo.media[1].timecode + sourceBuffer.timestampOffset,
segmentInfo.media[0].highest_end_time + sourceBuffer.timestampOffset,
test.done);
})
});
}, "Test sequence AppendMode appendBuffer(second media segment, then first media segment)");
</script>
</body>
</html>

View file

@ -0,0 +1,140 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBuffer.mode test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
assert_equals(sourceBuffer.mode, 'segments', 'default append mode should be \'segments\'');
test.done();
}, 'Test initial value of SourceBuffer.mode is "segments"');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
sourceBuffer.mode = 'sequence';
assert_equals(sourceBuffer.mode, 'sequence', 'mode after setting it to \'sequence\'');
// Setting a mode that is not in AppendMode IDL enum should be ignored and not cause exception.
sourceBuffer.mode = 'invalidmode';
sourceBuffer.mode = null;
sourceBuffer.mode = '';
sourceBuffer.mode = 'Segments';
assert_equals(sourceBuffer.mode, 'sequence', 'mode unchanged by attempts to set invalid modes');
sourceBuffer.mode = 'segments';
assert_equals(sourceBuffer.mode, 'segments', 'mode after setting it to \'segments\'');
test.done();
}, 'Test setting SourceBuffer.mode');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
mediaSource.removeSourceBuffer(sourceBuffer);
assert_throws('InvalidStateError',
function() { sourceBuffer.mode = 'segments'; },
'Setting valid sourceBuffer.mode on removed SourceBuffer should throw InvalidStateError.');
test.done();
}, 'Test setting a removed SourceBuffer\'s mode');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
sourceBuffer.appendBuffer(mediaData);
assert_true(sourceBuffer.updating, 'updating attribute is true');
assert_throws('InvalidStateError',
function() { sourceBuffer.mode = 'segments'; },
'Setting valid sourceBuffer.mode on updating SourceBuffer threw InvalidStateError.');
test.done();
}, 'Test setting SourceBuffer.mode while still updating');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
test.expectEvent(sourceBuffer, 'updateend', 'Append ended.');
sourceBuffer.appendBuffer(mediaData);
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, 'updating attribute is false');
test.expectEvent(mediaSource, 'sourceended', 'MediaSource sourceended event');
mediaSource.endOfStream();
assert_equals(mediaSource.readyState, 'ended', 'MediaSource readyState is \'ended\'');
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, 'ended', 'MediaSource readyState is \'ended\'');
test.expectEvent(mediaSource, 'sourceopen', 'MediaSource sourceopen event');
sourceBuffer.mode = 'segments';
assert_equals(mediaSource.readyState, 'open', 'MediaSource readyState is \'open\'');
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, 'open', 'MediaSource readyState is \'open\'');
test.done();
});
}, 'Test setting SourceBuffer.mode triggers parent MediaSource \'ended\' to \'open\' transition.');
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var fullMediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
var truncateAt = Math.floor(segmentInfo.media[0].size * 0.5); // Pick first 50% of segment bytes.
var partialMediaSegment = fullMediaSegment.subarray(0, truncateAt);
var mediaSegmentRemainder = fullMediaSegment.subarray(truncateAt);
// Append init segment.
test.expectEvent(sourceBuffer, 'updateend', 'Init segment append ended.');
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, 'updating attribute is false');
assert_equals(sourceBuffer.mode, 'segments');
sourceBuffer.mode = 'segments'; // No exception should occur.
assert_equals(sourceBuffer.timestampOffset, 0.0);
sourceBuffer.timestampOffset = 10.123456789; // No exception should occur.
assert_equals(sourceBuffer.timestampOffset, 10.123456789); // Super-precise offsets should round-trip.
// Append first part of media segment.
test.expectEvent(sourceBuffer, 'updateend', 'Partial media segment append ended.');
sourceBuffer.appendBuffer(partialMediaSegment);
});
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, 'updating attribute is false');
assert_equals(sourceBuffer.mode, 'segments');
assert_throws('InvalidStateError',
function() { sourceBuffer.mode = 'segments'; },
'Setting valid sourceBuffer.mode while still parsing media segment threw InvalidStateError.');
assert_equals(sourceBuffer.timestampOffset, 10.123456789);
assert_throws('InvalidStateError',
function() { sourceBuffer.timestampOffset = 20.0; },
'Setting valid sourceBuffer.timestampOffset while still parsing media segment threw InvalidStateError.');
// Append remainder of media segment.
test.expectEvent(sourceBuffer, 'updateend', 'Append ended of remainder of media segment.');
sourceBuffer.appendBuffer(mediaSegmentRemainder);
});
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, 'updating attribute is false');
assert_equals(sourceBuffer.mode, 'segments');
sourceBuffer.mode = 'segments'; // No exception should occur.
assert_equals(sourceBuffer.timestampOffset, 10.123456789);
sourceBuffer.timestampOffset = 20.0; // No exception should occur.
test.done();
});
}, 'Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment.');
</script>
</body>
</html>

View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBufferList test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function verifySourceBufferLists(mediaSource, expected)
{
assert_equals(mediaSource.sourceBuffers.length, expected.length, "sourceBuffers length");
assert_equals(mediaSource.activeSourceBuffers.length, 0, "activeSourceBuffers length");
for (var i = 0; i < expected.length; ++i)
assert_equals(mediaSource.sourceBuffers[i], expected[i], "Verifying mediaSource.sourceBuffers[" + i + "]");
}
mediasource_test(function(test, mediaElement, mediaSource)
{
test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
var sourceBufferA = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
var sourceBufferB = null;
test.waitForExpectedEvents(function()
{
test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
sourceBufferB = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
verifySourceBufferLists(mediaSource, [sourceBufferA, sourceBufferB]);
});
test.waitForExpectedEvents(function()
{
test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "sourceBuffers");
mediaSource.removeSourceBuffer(sourceBufferA);
verifySourceBufferLists(mediaSource, [sourceBufferB]);
test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
sourceBufferA = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
verifySourceBufferLists(mediaSource, [sourceBufferB, sourceBufferA]);
});
test.waitForExpectedEvents(function()
{
test.done();
});
}, "Test SourceBufferList event dispatching.");
mediasource_test(function(test, mediaElement, mediaSource)
{
test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
test.expectEvent(mediaSource.sourceBuffers, "addsourcebuffer", "sourceBuffers");
var sourceBufferA = mediaSource.addSourceBuffer(MediaSourceUtil.VIDEO_ONLY_TYPE);
var sourceBufferB = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_ONLY_TYPE);
verifySourceBufferLists(mediaSource, [sourceBufferA, sourceBufferB]);
test.waitForExpectedEvents(function()
{
verifySourceBufferLists(mediaSource, [sourceBufferA, sourceBufferB]);
// Force the media element to close the MediaSource object.
test.expectEvent(mediaSource.sourceBuffers, "removesourcebuffer", "sourceBuffers");
test.expectEvent(mediaSource, "sourceclose", "mediaSource closing");
mediaElement.src = "";
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.readyState, "closed", "mediaSource is closed.");
verifySourceBufferLists(mediaSource, []);
test.done();
});
}, "Test that only 1 removesourcebuffer event fires on each SourceBufferList when the MediaSource closes.");
</script>
</body>
</html>

View file

@ -0,0 +1,121 @@
<!DOCTYPE html>
<html>
<head>
<title>SourceBuffer.timestampOffset test cases.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="mediasource-util.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function simpleTimestampOffsetTest(value, expected, description)
{
mediasource_test(function(test, mediaElement, mediaSource)
{
var segmentInfo = MediaSourceUtil.SEGMENT_INFO;
var sourceBuffer = mediaSource.addSourceBuffer(segmentInfo.type);
if (expected == "TypeError") {
assert_throws({name: "TypeError"},
function() { sourceBuffer.timestampOffset = value; },
"setting timestampOffset to " + description + " throws an exception.");
} else {
sourceBuffer.timestampOffset = value;
assert_equals(sourceBuffer.timestampOffset, expected);
}
test.done();
}, "Test setting SourceBuffer.timestampOffset to " + description + ".");
}
simpleTimestampOffsetTest(10.5, 10.5, "a positive number");
simpleTimestampOffsetTest(-10.4, -10.4, "a negative number");
simpleTimestampOffsetTest(0, 0, "zero");
simpleTimestampOffsetTest(Number.POSITIVE_INFINITY, "TypeError", "positive infinity");
simpleTimestampOffsetTest(Number.NEGATIVE_INFINITY, "TypeError", "negative infinity");
simpleTimestampOffsetTest(Number.NaN, "TypeError", "NaN");
simpleTimestampOffsetTest(undefined, "TypeError", "undefined");
simpleTimestampOffsetTest(null, 0, "null");
simpleTimestampOffsetTest(false, 0, "false");
simpleTimestampOffsetTest(true, 1, "true");
simpleTimestampOffsetTest("10.5", 10.5, "a number string");
simpleTimestampOffsetTest("", 0, "an empty string");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
sourceBuffer.appendBuffer(initSegment);
test.waitForExpectedEvents(function()
{
test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
sourceBuffer.appendBuffer(mediaSegment);
});
test.waitForExpectedEvents(function()
{
mediaSource.endOfStream();
assert_equals(mediaSource.readyState, "ended");
mediaSource.sourceBuffers[0].timestampOffset = 2;
assert_equals(mediaSource.readyState, "open");
test.expectEvent(mediaSource, "sourceopen", "mediaSource fired 'sourceopen' event.");
});
test.waitForExpectedEvents(function()
{
test.done();
});
}, "Test setting timestampOffset in 'ended' state causes a transition to 'open'.");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var initSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
var mediaSegment = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
test.expectEvent(sourceBuffer, "updateend", "initSegment append ended.");
sourceBuffer.appendBuffer(initSegment);
assert_equals(mediaSource.sourceBuffers[0].timestampOffset, 0, "read initial value");
test.waitForExpectedEvents(function()
{
test.expectEvent(sourceBuffer, "updateend", "mediaSegment append ended.");
sourceBuffer.appendBuffer(mediaSegment);
assert_equals(mediaSource.sourceBuffers[0].timestampOffset, 0,
"No change to timestampoffset after segments mode init segment append");
});
test.waitForExpectedEvents(function()
{
assert_equals(mediaSource.sourceBuffers[0].timestampOffset, 0,
"No change to timestampoffset after segments mode media segment append");
test.done();
});
}, "Test getting the initial value of timestampOffset.");
mediasource_test(function(test, mediaElement, mediaSource)
{
var sourceBuffer = mediaSource.addSourceBuffer(MediaSourceUtil.AUDIO_VIDEO_TYPE);
assert_true(sourceBuffer != null, "New SourceBuffer returned");
mediaSource.removeSourceBuffer(sourceBuffer);
assert_true(mediaSource.sourceBuffers.length == 0, "MediaSource.sourceBuffers is empty");
assert_true(mediaSource.activeSourceBuffers.length == 0, "MediaSource.activesourceBuffers is empty");
assert_throws("InvalidStateError", function()
{
sourceBuffer.timestampOffset = 10;
});
test.done();
}, "Test setting timestampoffset after removing the sourcebuffer.");
</script>
</body>
</html>

View file

@ -0,0 +1,431 @@
(function(window) {
setup({ timeout: 12000 });
var SEGMENT_INFO_LIST = [
{
url: 'mp4/test.mp4',
type: 'video/mp4; codecs="mp4a.40.2,avc1.4d400d"',
duration: 6.0756,
init: { offset: 0, size: 1197 },
media: [
{ offset: 1241, size: 17845, timecode: 0.000000 },
{ offset: 19130, size: 5551, timecode: 0.464800 },
{ offset: 24725, size: 10944, timecode: 0.763600 },
{ offset: 35713, size: 7131, timecode: 0.863200 },
{ offset: 42888, size: 2513, timecode: 1.128800 },
{ offset: 45457, size: 3022, timecode: 1.261600 },
{ offset: 48479, size: 815, timecode: 1.427600 },
{ offset: 49338, size: 2818, timecode: 1.460800 },
{ offset: 52200, size: 11581, timecode: 1.593600 },
{ offset: 63825, size: 3003, timecode: 1.726400 },
{ offset: 66872, size: 6390, timecode: 1.892400 },
{ offset: 73306, size: 3740, timecode: 2.124800 },
{ offset: 77102, size: 11779, timecode: 2.324000 },
{ offset: 88881, size: 851, timecode: 2.490000 },
{ offset: 89776, size: 4236, timecode: 2.523200 },
{ offset: 94056, size: 9538, timecode: 2.755600 },
{ offset: 103638, size: 13295, timecode: 3.154000 },
{ offset: 116977, size: 309, timecode: 3.386400 },
{ offset: 117330, size: 5806, timecode: 3.419600 },
{ offset: 123180, size: 4392, timecode: 3.751600 },
{ offset: 127616, size: 15408, timecode: 3.984000 },
{ offset: 143068, size: 9899, timecode: 4.216400 },
{ offset: 153011, size: 11562, timecode: 4.780800 },
{ offset: 164617, size: 7398, timecode: 4.946800 },
{ offset: 172059, size: 5698, timecode: 5.212400 },
{ offset: 177801, size: 11682, timecode: 5.511200 },
{ offset: 189527, size: 3023, timecode: 5.677200 },
{ offset: 192594, size: 5726, timecode: 5.843200 },
]
},
{
url: 'webm/test.webm',
type: 'video/webm; codecs="vp8, vorbis"',
duration: 6.042,
init: { offset: 0, size: 4357 },
media: [
{ offset: 4357, size: 11830, timecode: 0 },
{ offset: 16187, size: 12588, timecode: 0.385 },
{ offset: 28775, size: 14588, timecode: 0.779 },
{ offset: 43363, size: 13023, timecode: 1.174 },
{ offset: 56386, size: 13127, timecode: 1.592 },
{ offset: 69513, size: 14456, timecode: 1.987 },
{ offset: 83969, size: 13458, timecode: 2.381 },
{ offset: 97427, size: 14566, timecode: 2.776 },
{ offset: 111993, size: 13201, timecode: 3.171 },
{ offset: 125194, size: 14061, timecode: 3.566 },
{ offset: 139255, size: 15353, timecode: 3.96 },
{ offset: 154608, size: 13618, timecode: 4.378 },
{ offset: 168226, size: 15094, timecode: 4.773 },
{ offset: 183320, size: 13069, timecode: 5.168 },
{ offset: 196389, size: 13788, timecode: 5.563 },
{ offset: 210177, size: 9009, timecode: 5.957 },
],
}
];
EventExpectationsManager = function(test)
{
this.test_ = test;
this.eventTargetList_ = [];
this.waitCallbacks_ = [];
};
EventExpectationsManager.prototype.expectEvent = function(object, eventName, description)
{
var eventInfo = { 'target': object, 'type': eventName, 'description': description};
var expectations = this.getExpectations_(object);
expectations.push(eventInfo);
var t = this;
var waitHandler = this.test_.step_func(this.handleWaitCallback_.bind(this));
var eventHandler = this.test_.step_func(function(event)
{
object.removeEventListener(eventName, eventHandler);
var expected = expectations[0];
assert_equals(event.target, expected.target, "Event target match.");
assert_equals(event.type, expected.type, "Event types match.");
assert_equals(eventInfo.description, expected.description, "Descriptions match for '" + event.type + "'.");
expectations.shift(1);
if (t.waitCallbacks_.length > 0)
setTimeout(waitHandler, 0);
});
object.addEventListener(eventName, eventHandler);
};
EventExpectationsManager.prototype.waitForExpectedEvents = function(callback)
{
this.waitCallbacks_.push(callback);
setTimeout(this.test_.step_func(this.handleWaitCallback_.bind(this)), 0);
};
EventExpectationsManager.prototype.expectingEvents = function()
{
for (var i = 0; i < this.eventTargetList_.length; ++i) {
if (this.eventTargetList_[i].expectations.length > 0) {
return true;
}
}
return false;
}
EventExpectationsManager.prototype.handleWaitCallback_ = function()
{
if (this.waitCallbacks_.length == 0 || this.expectingEvents())
return;
var callback = this.waitCallbacks_.shift(1);
callback();
};
EventExpectationsManager.prototype.getExpectations_ = function(target)
{
for (var i = 0; i < this.eventTargetList_.length; ++i) {
var info = this.eventTargetList_[i];
if (info.target == target) {
return info.expectations;
}
}
var expectations = [];
this.eventTargetList_.push({ 'target': target, 'expectations': expectations });
return expectations;
};
function loadData_(test, url, callback, isBinary)
{
var request = new XMLHttpRequest();
request.open("GET", url, true);
if (isBinary) {
request.responseType = 'arraybuffer';
}
request.onload = test.step_func(function(event)
{
if (request.status != 200) {
assert_unreached("Unexpected status code : " + request.status);
return;
}
var response = request.response;
if (isBinary) {
response = new Uint8Array(response);
}
callback(response);
});
request.onerror = test.step_func(function(event)
{
assert_unreached("Unexpected error");
});
request.send();
}
function openMediaSource_(test, mediaTag, callback)
{
var mediaSource = new MediaSource();
var mediaSourceURL = URL.createObjectURL(mediaSource);
var eventHandler = test.step_func(onSourceOpen);
function onSourceOpen(event)
{
mediaSource.removeEventListener('sourceopen', eventHandler);
URL.revokeObjectURL(mediaSourceURL);
callback(mediaSource);
}
mediaSource.addEventListener('sourceopen', eventHandler);
mediaTag.src = mediaSourceURL;
}
var MediaSourceUtil = {};
MediaSourceUtil.loadTextData = function(test, url, callback)
{
loadData_(test, url, callback, false);
};
MediaSourceUtil.loadBinaryData = function(test, url, callback)
{
loadData_(test, url, callback, true);
};
MediaSourceUtil.fetchManifestAndData = function(test, manifestFilename, callback)
{
var baseURL = '';
var manifestURL = baseURL + manifestFilename;
MediaSourceUtil.loadTextData(test, manifestURL, function(manifestText)
{
var manifest = JSON.parse(manifestText);
assert_true(MediaSource.isTypeSupported(manifest.type), manifest.type + " is supported.");
var mediaURL = baseURL + manifest.url;
MediaSourceUtil.loadBinaryData(test, mediaURL, function(mediaData)
{
callback(manifest.type, mediaData);
});
});
};
MediaSourceUtil.extractSegmentData = function(mediaData, info)
{
var start = info.offset;
var end = start + info.size;
return mediaData.subarray(start, end);
}
MediaSourceUtil.getMediaDataForPlaybackTime = function(mediaData, segmentInfo, playbackTimeToAdd)
{
assert_less_than_equal(playbackTimeToAdd, segmentInfo.duration);
var mediaInfo = segmentInfo.media;
var start = mediaInfo[0].offset;
var numBytes = 0;
var segmentIndex = 0;
while (segmentIndex < mediaInfo.length && mediaInfo[segmentIndex].timecode <= playbackTimeToAdd)
{
numBytes += mediaInfo[segmentIndex].size;
++segmentIndex;
}
return mediaData.subarray(start, numBytes + start);
}
function getFirstSupportedType(typeList)
{
for (var i = 0; i < typeList.length; ++i) {
if (window.MediaSource && MediaSource.isTypeSupported(typeList[i]))
return typeList[i];
}
return "";
}
function getSegmentInfo()
{
for (var i = 0; i < SEGMENT_INFO_LIST.length; ++i) {
var segmentInfo = SEGMENT_INFO_LIST[i];
if (window.MediaSource && MediaSource.isTypeSupported(segmentInfo.type)) {
return segmentInfo;
}
}
return null;
}
var audioOnlyTypes = ['audio/mp4;codecs="mp4a.40.2"', 'audio/webm;codecs="vorbis"'];
var videoOnlyTypes = ['video/mp4;codecs="avc1.4D4001"', 'video/webm;codecs="vp8"'];
var audioVideoTypes = ['video/mp4;codecs="avc1.4D4001,mp4a.40.2"', 'video/webm;codecs="vp8,vorbis"'];
MediaSourceUtil.AUDIO_ONLY_TYPE = getFirstSupportedType(audioOnlyTypes);
MediaSourceUtil.VIDEO_ONLY_TYPE = getFirstSupportedType(videoOnlyTypes);
MediaSourceUtil.AUDIO_VIDEO_TYPE = getFirstSupportedType(audioVideoTypes);
MediaSourceUtil.SEGMENT_INFO = getSegmentInfo();
MediaSourceUtil.getSubType = function(mimetype) {
var slashIndex = mimetype.indexOf("/");
var semicolonIndex = mimetype.indexOf(";");
if (slashIndex <= 0) {
assert_unreached("Invalid mimetype '" + mimetype + "'");
return;
}
var start = slashIndex + 1;
if (semicolonIndex >= 0) {
if (semicolonIndex <= start) {
assert_unreached("Invalid mimetype '" + mimetype + "'");
return;
}
return mimetype.substr(start, semicolonIndex - start)
}
return mimetype.substr(start);
};
MediaSourceUtil.append = function(test, sourceBuffer, data, callback)
{
function onUpdate() {
sourceBuffer.removeEventListener("update", onUpdate);
callback();
}
sourceBuffer.addEventListener("update", onUpdate);
test.failOnEvent(sourceBuffer, "error");
sourceBuffer.appendBuffer(data);
};
MediaSourceUtil.appendUntilEventFires = function(test, mediaElement, eventName, sourceBuffer, mediaData, segmentInfo, startingIndex)
{
var eventFired = false;
function onEvent() {
mediaElement.removeEventListener(eventName, onEvent);
eventFired = true;
}
mediaElement.addEventListener(eventName, onEvent);
var i = startingIndex;
var onAppendDone = function() {
if (eventFired)
return;
i++;
MediaSourceUtil.append(test, sourceBuffer, MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[i]), onAppendDone);
};
MediaSourceUtil.append(test, sourceBuffer, MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[i]), onAppendDone);
};
function addExtraTestMethods(test)
{
test.failOnEvent = function(object, eventName)
{
object.addEventListener(eventName, test.step_func(function(event)
{
assert_unreached("Unexpected event '" + eventName + "'");
}));
};
test.endOnEvent = function(object, eventName)
{
object.addEventListener(eventName, test.step_func(function(event) { test.done(); }));
};
test.eventExpectations_ = new EventExpectationsManager(test);
test.expectEvent = function(object, eventName, description)
{
test.eventExpectations_.expectEvent(object, eventName, description);
};
test.waitForExpectedEvents = function(callback)
{
test.eventExpectations_.waitForExpectedEvents(callback);
};
test.waitForCurrentTimeChange = function(mediaElement, callback)
{
var initialTime = mediaElement.currentTime;
var onTimeUpdate = test.step_func(function()
{
if (mediaElement.currentTime != initialTime) {
mediaElement.removeEventListener('timeupdate', onTimeUpdate);
callback();
}
});
mediaElement.addEventListener('timeupdate', onTimeUpdate);
}
var oldTestDone = test.done.bind(test);
test.done = function()
{
if (test.status == test.PASS) {
assert_false(test.eventExpectations_.expectingEvents(), "No pending event expectations.");
}
oldTestDone();
};
};
window['MediaSourceUtil'] = MediaSourceUtil;
window['media_test'] = function(testFunction, description, options)
{
options = options || {};
return async_test(function(test)
{
addExtraTestMethods(test);
testFunction(test);
}, description, options);
};
window['mediasource_test'] = function(testFunction, description, options)
{
return media_test(function(test)
{
var mediaTag = document.createElement("video");
document.body.appendChild(mediaTag);
test.removeMediaElement_ = true;
test.add_cleanup(function()
{
if (test.removeMediaElement_) {
document.body.removeChild(mediaTag);
test.removeMediaElement_ = false;
}
});
openMediaSource_(test, mediaTag, function(mediaSource)
{
testFunction(test, mediaTag, mediaSource);
});
}, description, options);
};
window['mediasource_testafterdataloaded'] = function(testFunction, description, options)
{
mediasource_test(function(test, mediaElement, mediaSource)
{
var segmentInfo = MediaSourceUtil.SEGMENT_INFO;
if (!segmentInfo) {
assert_unreached("No segment info compatible with this MediaSource implementation.");
return;
}
test.failOnEvent(mediaElement, 'error');
var sourceBuffer = mediaSource.addSourceBuffer(segmentInfo.type);
MediaSourceUtil.loadBinaryData(test, segmentInfo.url, function(mediaData)
{
testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData);
});
}, description, options);
}
function timeRangesToString(ranges)
{
var s = "{";
for (var i = 0; i < ranges.length; ++i) {
s += " [" + ranges.start(i).toFixed(3) + ", " + ranges.end(i).toFixed(3) + ")";
}
return s + " }";
}
window['assertBufferedEquals'] = function(obj, expected, description)
{
var actual = timeRangesToString(obj.buffered);
assert_equals(actual, expected, description);
};
})(window);

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-a-128k-44100Hz-1ch.mp4",
"type": "audio/mp4;codecs=\"mp4a.40.2\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-a-192k-44100Hz-1ch.mp4",
"type": "audio/mp4;codecs=\"mp4a.40.2\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001,mp4a.40.2\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-v-128k-320x240-24fps-8kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-v-128k-320x240-30fps-10kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-v-128k-640x480-30fps-10kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001\""
}

View file

@ -0,0 +1,4 @@
{
"url": "mp4/test-v-256k-320x240-30fps-10kfr.mp4",
"type": "video/mp4;codecs=\"avc1.4D4001\""
}

Binary file not shown.

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-a-128k-44100Hz-1ch.webm",
"type": "audio/webm;codecs=\"vorbis\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-a-192k-44100Hz-1ch.webm",
"type": "audio/webm;codecs=\"vorbis\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm",
"type": "video/webm;codecs=\"vp8,vorbis\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-av-384k-44100Hz-1ch-640x480-30fps-10kfr.webm",
"type": "video/webm;codecs=\"vp8,vorbis\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-av-448k-44100Hz-1ch-640x480-30fps-10kfr.webm",
"type": "video/webm;codecs=\"vp8,vorbis\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-av-640k-44100Hz-1ch-640x480-30fps-10kfr.webm",
"type": "video/webm;codecs=\"vp8,vorbis\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-v-128k-320x240-24fps-8kfr.webm",
"type": "video/webm;codecs=\"vp8\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-v-128k-320x240-30fps-10kfr.webm",
"type": "video/webm;codecs=\"vp8\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-v-128k-640x480-30fps-10kfr.webm",
"type": "video/webm;codecs=\"vp8\""
}

View file

@ -0,0 +1,4 @@
{
"url": "webm/test-v-256k-320x240-30fps-10kfr.webm",
"type": "video/webm;codecs=\"vp8\""
}