summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/media-source/mse-for-webcodecs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/media-source/mse-for-webcodecs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/media-source/mse-for-webcodecs')
-rw-r--r--testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-addsourcebuffer.html203
-rw-r--r--testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-appendencodedchunks-play.html83
-rw-r--r--testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/vp9.mp4bin0 -> 6159 bytes
3 files changed, 286 insertions, 0 deletions
diff --git a/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-addsourcebuffer.html b/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-addsourcebuffer.html
new file mode 100644
index 0000000000..cc9cdc2b50
--- /dev/null
+++ b/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-addsourcebuffer.html
@@ -0,0 +1,203 @@
+<!DOCTYPE html>
+<html>
+ <title>Test MediaSource addSourceBuffer overloads for WebCodecs Audio/VideoDecoderConfigs</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+setup(() => {
+ assert_implements(
+ SourceBuffer.prototype.hasOwnProperty('appendEncodedChunks'),
+ 'SourceBuffer prototype hasOwnProperty "appendEncodedChunks", used ' +
+ 'here to feature detect MSE-for-WebCodecs implementation.');
+});
+
+testInvalidArguments();
+testValidArguments();
+
+function getValidAudioConfig() {
+ // TODO(crbug.com/1144908): Consider confirming with WebCodecs'
+ // isConfigSupported() once that API is available.
+ return {
+ codec: 'opus',
+ sampleRate: 48000,
+ numberOfChannels: 2
+ };
+}
+
+function getValidVideoConfig() {
+ // TODO(crbug.com/1144908): Consider confirming with WebCodecs'
+ // isConfigSupported() once that API is available.
+ return { codec: 'vp09.00.10.08' };
+}
+
+function testInvalidArguments() {
+ const INVALID_CASES = [
+ { arg: null,
+ name: 'null' },
+ { arg: undefined,
+ name: 'undefined' },
+ { arg: { },
+ name: '{ empty dictionary }' },
+ {
+ arg: {
+ audioConfig: getValidAudioConfig(),
+ videoConfig: getValidVideoConfig()
+ },
+ name: '{ valid audioConfig and videoConfig }',
+ },
+ {
+ arg: {
+ audioConfig: {
+ codec: 'bogus',
+ sampleRate: 48000,
+ numberOfChannels: 2
+ }
+ },
+ name: 'bad audio config codec',
+ },
+ { arg: { videoConfig: { codec: 'bogus' } },
+ name: 'bad video config codec' },
+ { arg: { audioConfig: { sampleRate: 48000, numberOfChannels: 2 } },
+ name: 'audio config missing required member "codec"' },
+ { arg: { videoConfig: { } },
+ name: 'video config missing required member "codec"' },
+ ];
+
+ [ 'closed', 'open', 'ended' ].forEach(readyStateScenario => {
+ INVALID_CASES.forEach(invalidCase => {
+ runAddSourceBufferTest(invalidCase['arg'] /* argument */,
+ false /* isValidArgument */,
+ invalidCase['name'] /* argumentDescription */,
+ readyStateScenario);
+ });
+ });
+}
+
+function testValidArguments() {
+ const VALID_CASES = [
+ {
+ arg: {
+ audioConfig: getValidAudioConfig()
+ },
+ name: 'valid audioConfig'
+ },
+ {
+ arg: {
+ videoConfig: getValidVideoConfig()
+ },
+ name: 'valid videoConfig'
+ },
+ ];
+
+ [ 'closed', 'open', 'ended' ].forEach(readyStateScenario => {
+ VALID_CASES.forEach(validCase => {
+ runAddSourceBufferTest(
+ validCase['arg'] /* argument */,
+ true /* isValidArgument */,
+ validCase['name'] /* argumentDescription */,
+ readyStateScenario);
+ });
+ });
+}
+
+async function getClosedMediaSource(test) {
+ let mediaSource = new MediaSource();
+ assert_equals(mediaSource.readyState, 'closed');
+ return mediaSource;
+}
+
+async function getOpenMediaSource(test) {
+ return new Promise(async resolve => {
+ const v = document.createElement('video');
+ const mediaSource = new MediaSource();
+ const url = URL.createObjectURL(mediaSource);
+ mediaSource.addEventListener('sourceopen', test.step_func(() => {
+ URL.revokeObjectURL(url);
+ assert_equals(mediaSource.readyState, 'open', 'MediaSource is open');
+ resolve(mediaSource);
+ }), { once: true });
+ v.src = url;
+ });
+}
+
+async function getEndedMediaSource(test) {
+ let mediaSource = await getOpenMediaSource(test);
+ assert_equals(mediaSource.readyState, 'open', 'MediaSource is open');
+ mediaSource.endOfStream();
+ assert_equals(mediaSource.readyState, 'ended', 'MediaSource is ended');
+ return mediaSource;
+}
+
+function runAddSourceBufferTest(argument, isValidArgument, argumentDescription, readyStateScenario) {
+ const testDescription = 'addSourceBuffer call with ' +
+ (isValidArgument ? 'valid' : 'invalid') +
+ ' argument ' + argumentDescription + ' while MediaSource readyState is ' +
+ readyStateScenario;
+
+ switch(readyStateScenario) {
+ case 'closed':
+ promise_test(async t => {
+ let mediaSource = await getClosedMediaSource(t);
+ assert_equals(mediaSource.readyState, 'closed');
+ let sourceBuffer;
+ if (isValidArgument) {
+ assert_throws_dom('InvalidStateError',
+ () => { sourceBuffer = mediaSource.addSourceBuffer(argument); },
+ 'addSourceBuffer(valid config) throws InvalidStateError if MediaSource is "closed"');
+ assert_equals(sourceBuffer, undefined,
+ 'addSourceBuffer result for valid config while "closed" should be exception');
+ } else {
+ assert_throws_js(TypeError,
+ () => { sourceBuffer = mediaSource.addSourceBuffer(argument); },
+ 'addSourceBuffer(invalid config) throws TypeError if MediaSource is "closed"');
+ assert_equals(sourceBuffer, undefined,
+ 'addSourceBuffer result for invalid config while "closed" should be exception');
+ }
+ }, testDescription);
+ break;
+ case 'open':
+ promise_test(async t => {
+ let mediaSource = await getOpenMediaSource(t);
+ assert_equals(mediaSource.readyState, 'open', 'MediaSource is open');
+ let sourceBuffer;
+ if (isValidArgument) {
+ sourceBuffer = mediaSource.addSourceBuffer(argument);
+ assert_true(sourceBuffer instanceof SourceBuffer,
+ 'addSourceBuffer result for valid config while "open" should be a SourceBuffer instance');
+ } else {
+ assert_throws_js(TypeError,
+ () => { sourceBuffer = mediaSource.addSourceBuffer(argument); },
+ 'addSourceBuffer(invalid config) throws TypeError if MediaSource is "open"');
+ assert_equals(sourceBuffer, undefined,
+ 'addSourceBufferResult for invalid config while "open" should be exception');
+ }
+ }, testDescription);
+ break;
+ case 'ended':
+ promise_test(async t => {
+ let mediaSource = await getEndedMediaSource(t);
+ let sourceBuffer;
+ if (isValidArgument) {
+ assert_throws_dom('InvalidStateError',
+ () => { sourceBuffer = mediaSource.addSourceBuffer(argument); },
+ 'addSourceBuffer(valid config) throws InvalidStateError if MediaSource is "ended"');
+ assert_equals(sourceBuffer, undefined,
+ 'addSourceBuffer result for valid config while "ended" should be exception');
+ } else {
+ assert_throws_js(TypeError,
+ () => { sourceBuffer = mediaSource.addSourceBuffer(argument); },
+ 'addSourceBuffer(invalid config) throws TypeError if MediaSource is "ended"');
+ assert_equals(sourceBuffer, undefined,
+ 'addSourceBuffer result for invalid config while "ended" should be exception');
+ }
+ }, testDescription);
+ break;
+ default:
+ assert_unreached('Invalid readyStateScenario ' + readyStateScenario);
+ break;
+ }
+}
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-appendencodedchunks-play.html b/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-appendencodedchunks-play.html
new file mode 100644
index 0000000000..4df317a537
--- /dev/null
+++ b/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/mediasource-webcodecs-appendencodedchunks-play.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+ <title>Test basic encoded chunk buffering and playback with MediaSource</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+setup(() => {
+ assert_implements(
+ SourceBuffer.prototype.hasOwnProperty('appendEncodedChunks'),
+ 'SourceBuffer prototype hasOwnProperty "appendEncodedChunks", used ' +
+ 'here to feature detect MSE-for-WebCodecs implementation.');
+});
+
+// TODO(crbug.com/1144908): Consider extracting metadata into helper library
+// shared with webcodecs tests. This metadata is adapted from webcodecs/video-decoder-any.js.
+let vp9 = {
+ async buffer() { return (await fetch('vp9.mp4')).arrayBuffer(); },
+ // Note, file might not actually be level 1. See original metadata in webcodecs test suite.
+ codec: "vp09.00.10.08",
+ frames: [{offset: 44, size: 3315, type: 'key'},
+ {offset: 3359, size: 203, type: 'delta'},
+ {offset: 3562, size: 245, type: 'delta'},
+ {offset: 3807, size: 172, type: 'delta'},
+ {offset: 3979, size: 312, type: 'delta'},
+ {offset: 4291, size: 170, type: 'delta'},
+ {offset: 4461, size: 195, type: 'delta'},
+ {offset: 4656, size: 181, type: 'delta'},
+ {offset: 4837, size: 356, type: 'delta'},
+ {offset: 5193, size: 159, type: 'delta'}]
+};
+
+async function getOpenMediaSource(t) {
+ return new Promise(async resolve => {
+ const v = document.createElement('video');
+ document.body.appendChild(v);
+ const mediaSource = new MediaSource();
+ const url = URL.createObjectURL(mediaSource);
+ mediaSource.addEventListener('sourceopen', t.step_func(() => {
+ URL.revokeObjectURL(url);
+ assert_equals(mediaSource.readyState, 'open', 'MediaSource is open');
+ resolve([ v, mediaSource ]);
+ }), { once: true });
+ v.src = url;
+ });
+}
+
+promise_test(async t => {
+ let buffer = await vp9.buffer();
+ let [ videoElement, mediaSource ] = await getOpenMediaSource(t);
+ videoElement.controls = true; // Makes early prototype demo playback easier to control manually.
+ let sourceBuffer = mediaSource.addSourceBuffer({ videoConfig: { codec: vp9.codec } });
+ let next_timestamp = 0;
+ let frame_duration = 100 * 1000; // 100 milliseconds
+ // forEach with async callbacks makes it too easy to have uncaught rejections
+ // that don't fail this promise_test or even emit harness error.
+ // Iterating explicitly instead.
+ for (i = 0; i < vp9.frames.length; i++, next_timestamp += frame_duration) {
+ let frame_metadata = vp9.frames[i];
+ await sourceBuffer.appendEncodedChunks(new EncodedVideoChunk( {
+ type: frame_metadata.type,
+ timestamp: next_timestamp,
+ duration: frame_duration,
+ data: new Uint8Array(buffer, frame_metadata.offset, frame_metadata.size)
+ }));
+ }
+
+ mediaSource.endOfStream();
+
+ return new Promise( (resolve, reject) => {
+ videoElement.onended = resolve;
+ videoElement.onerror = reject;
+ videoElement.play();
+ });
+
+}, "Buffer EncodedVideoChunks (VP9) one-by-one and play them with MSE");
+
+// TODO(crbug.com/1144908): More exhaustive tests (multiple sourcebuffers,
+// varying append patterns, invalid append patterns; eventually more codecs,
+// out-of-order DTS, durations, etc.)
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/vp9.mp4 b/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/vp9.mp4
new file mode 100644
index 0000000000..7553e5cae9
--- /dev/null
+++ b/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/vp9.mp4
Binary files differ