diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/media-source/mse-for-webcodecs | |
parent | Initial commit. (diff) | |
download | firefox-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')
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 Binary files differnew file mode 100644 index 0000000000..7553e5cae9 --- /dev/null +++ b/testing/web-platform/tests/media-source/mse-for-webcodecs/tentative/vp9.mp4 |