summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webcodecs
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webcodecs')
-rw-r--r--testing/web-platform/tests/webcodecs/audio-data.any.js533
-rw-r--r--testing/web-platform/tests/webcodecs/audio-decoder.https.any.js13
-rw-r--r--testing/web-platform/tests/webcodecs/video-decoder.https.any.js8
-rw-r--r--testing/web-platform/tests/webcodecs/video-encoder-config.https.any.js8
4 files changed, 332 insertions, 230 deletions
diff --git a/testing/web-platform/tests/webcodecs/audio-data.any.js b/testing/web-platform/tests/webcodecs/audio-data.any.js
index 4c2d96ab80..d5d9506477 100644
--- a/testing/web-platform/tests/webcodecs/audio-data.any.js
+++ b/testing/web-platform/tests/webcodecs/audio-data.any.js
@@ -2,19 +2,20 @@
// META: script=/common/media.js
// META: script=/webcodecs/utils.js
-var defaultInit =
- {
- timestamp: 1234,
- channels: 2,
- sampleRate: 8000,
- frames: 100,
- }
-
-function
-createDefaultAudioData() {
+var defaultInit = {
+ timestamp: 1234,
+ channels: 2,
+ sampleRate: 8000,
+ frames: 100,
+};
+
+function createDefaultAudioData() {
return make_audio_data(
- defaultInit.timestamp, defaultInit.channels, defaultInit.sampleRate,
- defaultInit.frames);
+ defaultInit.timestamp,
+ defaultInit.channels,
+ defaultInit.sampleRate,
+ defaultInit.frames
+ );
}
test(t => {
@@ -128,230 +129,302 @@ test(t => {
data.close();
}, 'Test we can construct AudioData with a negative timestamp.');
-
-// Each test vector represents two channels of data in the following arbitrary
-// layout: <min, zero, max, min, max / 2, min / 2, zero, max, zero, zero>.
-const testVectorFrames = 5;
-const testVectorChannels = 2;
-const testVectorInterleavedResult =
- [[-1.0, 1.0, 0.5, 0.0, 0.0], [0.0, -1.0, -0.5, 1.0, 0.0]];
-const testVectorPlanarResult =
- [[-1.0, 0.0, 1.0, -1.0, 0.5], [-0.5, 0.0, 1.0, 0.0, 0.0]];
-
-test(t => {
- const INT8_MIN = (-0x7f - 1);
- const INT8_MAX = 0x7f;
- const UINT8_MAX = 0xff;
-
- const testVectorUint8 = [
- 0, -INT8_MIN, UINT8_MAX, 0, INT8_MAX / 2 + 128, INT8_MIN / 2 + 128,
- -INT8_MIN, UINT8_MAX, -INT8_MIN, -INT8_MIN
- ];
-
- let data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Uint8Array(testVectorUint8),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 'u8'
- });
-
- const epsilon = 1.0 / (UINT8_MAX - 1);
-
- let dest = new Float32Array(data.numberOfFrames);
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[0], epsilon, 'interleaved channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[1], epsilon, 'interleaved channel 1');
-
- data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Uint8Array(testVectorUint8),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 'u8-planar'
- });
-
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[0], epsilon, 'planar channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[1], epsilon, 'planar channel 1');
-}, 'Test conversion of uint8 data to float32');
-
-test(t => {
- const INT16_MIN = (-0x7fff - 1);
- const INT16_MAX = 0x7fff;
- const testVectorInt16 = [
- INT16_MIN, 0, INT16_MAX, INT16_MIN, INT16_MAX / 2, INT16_MIN / 2, 0,
- INT16_MAX, 0, 0
- ];
-
- let data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Int16Array(testVectorInt16),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 's16'
- });
-
- const epsilon = 1.0 / (INT16_MAX + 1);
-
- let dest = new Float32Array(data.numberOfFrames);
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[0], epsilon, 'interleaved channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[1], epsilon, 'interleaved channel 1');
-
- data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Int16Array(testVectorInt16),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 's16-planar'
- });
-
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[0], epsilon, 'planar channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[1], epsilon, 'planar channel 1');
-}, 'Test conversion of int16 data to float32');
-
-test(t => {
- const INT32_MIN = (-0x7fffffff - 1);
- const INT32_MAX = 0x7fffffff;
- const testVectorInt32 = [
- INT32_MIN, 0, INT32_MAX, INT32_MIN, INT32_MAX / 2, INT32_MIN / 2, 0,
- INT32_MAX, 0, 0
- ];
-
- let data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Int32Array(testVectorInt32),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 's32'
- });
-
- const epsilon = 1.0 / INT32_MAX;
-
- let dest = new Float32Array(data.numberOfFrames);
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[0], epsilon, 'interleaved channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[1], epsilon, 'interleaved channel 1');
-
- data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Int32Array(testVectorInt32),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 's32-planar'
- });
-
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[0], epsilon, 'planar channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[1], epsilon, 'planar channel 1');
-}, 'Test conversion of int32 data to float32');
-
test(t => {
- const testVectorFloat32 =
- [-1.0, 0.0, 1.0, -1.0, 0.5, -0.5, 0.0, 1.0, 0.0, 0.0];
-
- let data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Float32Array(testVectorFloat32),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 'f32'
- });
-
- const epsilon = 0;
-
- let dest = new Float32Array(data.numberOfFrames);
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[0], epsilon, 'interleaved channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorInterleavedResult[1], epsilon, 'interleaved channel 1');
-
- data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Float32Array(testVectorFloat32),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 'f32-planar'
- });
+ let audio_data_init = {
+ timestamp: 0,
+ data: new Float32Array([1,2,3,4,5,6,7,8]),
+ numberOfFrames: 4,
+ numberOfChannels: 2,
+ sampleRate: 44100,
+ format: 'f32',
+ };
+ let audioData = new AudioData(audio_data_init);
+ let dest = new Float32Array(8);
+ assert_throws_js(
+ RangeError, () => audioData.copyTo(dest, {planeIndex: 1}),
+ 'copyTo from interleaved data with non-zero planeIndex throws');
+ audioData.close();
+}, 'Test that copyTo throws if copying from interleaved with a non-zero planeIndex');
+
+// Indices to pick a particular specific value in a specific sample-format
+const MIN = 0; // Minimum sample value, max amplitude
+const MAX = 1; // Maximum sample value, max amplitude
+const HALF = 2; // Half the maximum sample value, positive
+const NEGATIVE_HALF = 3; // Half the maximum sample value, negative
+const BIAS = 4; // Center of the range, silence
+const DISCRETE_STEPS = 5; // Number of different value for a type.
+
+function pow2(p) {
+ return 2 ** p;
+}
+// Rounding operations for conversion, currently always floor (round towards
+// zero).
+let r = Math.floor.bind(this);
+
+const TEST_VALUES = {
+ u8: [0, 255, 191, 64, 128, 256],
+ s16: [
+ -pow2(15),
+ pow2(15) - 1,
+ r((pow2(15) - 1) / 2),
+ r(-pow2(15) / 2),
+ 0,
+ pow2(16),
+ ],
+ s32: [
+ -pow2(31),
+ pow2(31) - 1,
+ r((pow2(31) - 1) / 2),
+ r(-pow2(31) / 2),
+ 0,
+ pow2(32),
+ ],
+ f32: [-1.0, 1.0, 0.5, -0.5, 0, pow2(24)],
+};
+
+const TEST_TEMPLATE = {
+ channels: 2,
+ frames: 5,
+ // Each test is run with an element of the cartesian product of a pair of
+ // elements of the set of type in [u8, s16, s32, f32]
+ // For each test, this template is copied and the values replaced with the
+ // appropriate values for this particular type.
+ // For each test, copy this template and replace the number by the appropriate
+ // number for this type
+ testInput: [MIN, BIAS, MAX, MIN, HALF, NEGATIVE_HALF, BIAS, MAX, BIAS, BIAS],
+ testVectorInterleavedResult: [
+ [MIN, MAX, HALF, BIAS, BIAS],
+ [BIAS, MIN, NEGATIVE_HALF, MAX, BIAS],
+ ],
+ testVectorPlanarResult: [
+ [MIN, BIAS, MAX, MIN, HALF],
+ [NEGATIVE_HALF, BIAS, MAX, BIAS, BIAS],
+ ],
+};
+
+function isInteger(type) {
+ switch (type) {
+ case "u8":
+ case "s16":
+ case "s32":
+ return true;
+ case "f32":
+ return false;
+ default:
+ throw "invalid type";
+ }
+}
- data.copyTo(dest, {planeIndex: 0, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[0], epsilon, 'planar channel 0');
- data.copyTo(dest, {planeIndex: 1, format: 'f32-planar'});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[1], epsilon, 'planar channel 1');
-}, 'Test conversion of float32 data to float32');
+// This is the complex part: carefully select an acceptable error value
+// depending on various factors: expected destination value, source type,
+// destination type. This is designed to be strict but reachable with simple
+// sample format transformation (no dithering or complex transformation).
+function epsilon(expectedDestValue, sourceType, destType) {
+ // Strict comparison if not converting
+ if (sourceType == destType) {
+ return 0.0;
+ }
+ // There are three cases in which the maximum value cannot be reached, when
+ // converting from a smaller integer sample type to a wider integer sample
+ // type:
+ // - u8 to s16
+ // - u8 to s32
+ // - s16 to u32
+ if (expectedDestValue == TEST_VALUES[destType][MAX]) {
+ if (sourceType == "u8" && destType == "s16") {
+ return expectedDestValue - 32511; // INT16_MAX - 2 << 7 + 1
+ } else if (sourceType == "u8" && destType == "s32") {
+ return expectedDestValue - 2130706432; // INT32_MAX - (2 << 23) + 1
+ } else if (sourceType == "s16" && destType == "s32") {
+ return expectedDestValue - 2147418112; // INT32_MAX - UINT16_MAX
+ }
+ }
+ // Min and bias value are correctly mapped for all integer sample-types
+ if (isInteger(sourceType) && isInteger(destType)) {
+ if (expectedDestValue == TEST_VALUES[destType][MIN] ||
+ expectedDestValue == TEST_VALUES[destType][BIAS]) {
+ return 0.0;
+ }
+ }
+ // If converting from float32 to u8 or s16, allow choosing the rounding
+ // direction. s32 has higher resolution than f32 in [-1.0,1.0] (24 bits of
+ // mantissa)
+ if (!isInteger(sourceType) && isInteger(destType) && destType != "s32") {
+ return 1.0;
+ }
+ // In all other cases, expect an accuracy that depends on the source type and
+ // the destination type.
+ // The resolution of the source type.
+ var sourceResolution = TEST_VALUES[sourceType][DISCRETE_STEPS];
+ // The resolution of the destination type.
+ var destResolution = TEST_VALUES[destType][DISCRETE_STEPS];
+ // Computations should be exact if going from high resolution to low resolution.
+ if (sourceResolution > destResolution) {
+ return 0.0;
+ } else {
+ // Something that approaches the precision imbalance
+ return destResolution / sourceResolution;
+ }
+}
-test(t => {
- const testVectorFloat32 =
- [-1.0, 0.0, 1.0, -1.0, 0.5, -0.5, 0.0, 1.0, 0.0, 0.0];
+// Fill the template above with the values for a particular type
+function get_type_values(type) {
+ let cloned = structuredClone(TEST_TEMPLATE);
+ cloned.testInput = Array.from(
+ cloned.testInput,
+ idx => TEST_VALUES[type][idx]
+ );
+ cloned.testVectorInterleavedResult = Array.from(
+ cloned.testVectorInterleavedResult,
+ c => {
+ return Array.from(c, idx => {
+ return TEST_VALUES[type][idx];
+ });
+ }
+ );
+ cloned.testVectorPlanarResult = Array.from(
+ cloned.testVectorPlanarResult,
+ c => {
+ return Array.from(c, idx => {
+ return TEST_VALUES[type][idx];
+ });
+ }
+ );
+ return cloned;
+}
- let data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Float32Array(testVectorFloat32),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 'f32'
- });
+function typeToArrayType(type) {
+ switch (type) {
+ case "u8":
+ return Uint8Array;
+ case "s16":
+ return Int16Array;
+ case "s32":
+ return Int32Array;
+ case "f32":
+ return Float32Array;
+ default:
+ throw "Unexpected";
+ }
+}
- const epsilon = 0;
+function arrayTypeToType(array) {
+ switch (array.constructor) {
+ case Uint8Array:
+ return "u8";
+ case Int16Array:
+ return "s16";
+ case Int32Array:
+ return "s32";
+ case Float32Array:
+ return "f32";
+ default:
+ throw "Unexpected";
+ }
+}
- // Call copyTo() without specifying a format, for interleaved data.
- let dest = new Float32Array(data.numberOfFrames * testVectorChannels);
- data.copyTo(dest, {planeIndex: 0});
- assert_array_approx_equals(
- dest, testVectorFloat32, epsilon, 'interleaved data');
+function check_array_equality(values, expected, sourceType, message, assert_func) {
+ if (values.length != expected.length) {
+ throw "Array not of the same length";
+ }
+ for (var i = 0; i < values.length; i++) {
+ var eps = epsilon(expected[i], sourceType, arrayTypeToType(values));
+ assert_func(
+ Math.abs(expected[i] - values[i]) <= eps,
+ `Got ${values[i]} but expected result ${
+ expected[i]
+ } at index ${i} when converting from ${sourceType} to ${arrayTypeToType(
+ values
+ )}, epsilon ${eps}`
+ );
+ }
+ assert_func(
+ true,
+ `${values} is equal to ${expected} when converting from ${sourceType} to ${arrayTypeToType(
+ values
+ )}`
+ );
+}
- assert_throws_js(RangeError, () => {
- data.copyTo(dest, {planeIndex: 1});
- }, 'Interleaved AudioData cannot copy out planeIndex > 0');
+function conversionTest(sourceType, destinationType) {
+ test(function (t) {
+ var test = get_type_values(sourceType);
+ var result = get_type_values(destinationType);
+
+ var sourceArrayCtor = typeToArrayType(sourceType);
+ var destArrayCtor = typeToArrayType(destinationType);
+
+ let data = new AudioData({
+ timestamp: defaultInit.timestamp,
+ data: new sourceArrayCtor(test.testInput),
+ numberOfFrames: test.frames,
+ numberOfChannels: test.channels,
+ sampleRate: defaultInit.sampleRate,
+ format: sourceType,
+ });
+
+ // All conversions can be supported, but conversion of any type to f32-planar
+ // MUST be supported.
+ var assert_func = destinationType == "f32" ? assert_true : assert_implements_optional;
+ let dest = new destArrayCtor(data.numberOfFrames);
+ data.copyTo(dest, { planeIndex: 0, format: destinationType + "-planar" });
+ check_array_equality(
+ dest,
+ result.testVectorInterleavedResult[0],
+ sourceType,
+ "interleaved channel 0",
+ assert_func
+ );
+ data.copyTo(dest, { planeIndex: 1, format: destinationType + "-planar" });
+ check_array_equality(
+ dest,
+ result.testVectorInterleavedResult[1],
+ sourceType,
+ "interleaved channel 0",
+ assert_func
+ );
+ let destInterleaved = new destArrayCtor(data.numberOfFrames * data.numberOfChannels);
+ data.copyTo(destInterleaved, { planeIndex: 0, format: destinationType });
+ check_array_equality(
+ destInterleaved,
+ result.testInput,
+ sourceType,
+ "copyTo from interleaved to interleaved (conversion only)",
+ assert_implements_optional
+ );
+
+ data = new AudioData({
+ timestamp: defaultInit.timestamp,
+ data: new sourceArrayCtor(test.testInput),
+ numberOfFrames: test.frames,
+ numberOfChannels: test.channels,
+ sampleRate: defaultInit.sampleRate,
+ format: sourceType + "-planar",
+ });
+
+ data.copyTo(dest, { planeIndex: 0, format: destinationType + "-planar" });
+ check_array_equality(
+ dest,
+ result.testVectorPlanarResult[0],
+ sourceType,
+ "planar channel 0",
+ assert_func,
+ );
+ data.copyTo(dest, { planeIndex: 1, format: destinationType + "-planar" });
+ check_array_equality(
+ dest,
+ result.testVectorPlanarResult[1],
+ sourceType,
+ "planar channel 1",
+ assert_func
+ );
+ // Planar to interleaved isn't supported
+ }, `Test conversion of ${sourceType} to ${destinationType}`);
+}
- data = new AudioData({
- timestamp: defaultInit.timestamp,
- data: new Float32Array(testVectorFloat32),
- numberOfFrames: testVectorFrames,
- numberOfChannels: testVectorChannels,
- sampleRate: defaultInit.sampleRate,
- format: 'f32-planar'
+const TYPES = ["u8", "s16", "s32", "f32"];
+ TYPES.forEach(sourceType => {
+ TYPES.forEach(destinationType => {
+ conversionTest(sourceType, destinationType);
});
-
- // Call copyTo() without specifying a format, for planar data.
- dest = new Float32Array(data.numberOfFrames);
- data.copyTo(dest, {planeIndex: 0});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[0], epsilon, 'planar channel 0');
- data.copyTo(dest, {planeIndex: 1});
- assert_array_approx_equals(
- dest, testVectorPlanarResult[1], epsilon, 'planar channel 1');
-}, 'Test copying out planar and interleaved data');
+});
diff --git a/testing/web-platform/tests/webcodecs/audio-decoder.https.any.js b/testing/web-platform/tests/webcodecs/audio-decoder.https.any.js
index 79ba22157a..666d3a159f 100644
--- a/testing/web-platform/tests/webcodecs/audio-decoder.https.any.js
+++ b/testing/web-platform/tests/webcodecs/audio-decoder.https.any.js
@@ -1,6 +1,10 @@
// META: global=window,dedicatedworker
// META: script=/webcodecs/utils.js
+
+const detachedArrayBuffer = new ArrayBuffer(4);
+var b = detachedArrayBuffer.transferToFixedLength();
+
const invalidConfigs = [
{
comment: 'Missing codec',
@@ -47,6 +51,15 @@ const invalidConfigs = [
numberOfChannels: 0,
},
},
+ {
+ comment: 'Valid configuration except detached description',
+ config: {
+ codec: 'opus',
+ sampleRate: 8000,
+ numberOfChannels: 1,
+ description: detachedArrayBuffer
+ },
+ },
];
invalidConfigs.forEach(entry => {
diff --git a/testing/web-platform/tests/webcodecs/video-decoder.https.any.js b/testing/web-platform/tests/webcodecs/video-decoder.https.any.js
index 77a610bd4e..5b3193b8c3 100644
--- a/testing/web-platform/tests/webcodecs/video-decoder.https.any.js
+++ b/testing/web-platform/tests/webcodecs/video-decoder.https.any.js
@@ -1,5 +1,9 @@
// META: global=window,dedicatedworker
// META: script=/webcodecs/utils.js
+//
+
+const detachedArrayBuffer = new ArrayBuffer(4);
+var b = detachedArrayBuffer.transferToFixedLength();
const invalidConfigs = [
{
@@ -10,6 +14,10 @@ const invalidConfigs = [
comment: 'Empty codec',
config: {codec: ''},
},
+ {
+ comment: 'Valid codec, detached description',
+ config: {codec: 'vp8', description: detachedArrayBuffer},
+ },
]; // invalidConfigs
invalidConfigs.forEach(entry => {
diff --git a/testing/web-platform/tests/webcodecs/video-encoder-config.https.any.js b/testing/web-platform/tests/webcodecs/video-encoder-config.https.any.js
index 5011bfdd0a..8d554e4f4d 100644
--- a/testing/web-platform/tests/webcodecs/video-encoder-config.https.any.js
+++ b/testing/web-platform/tests/webcodecs/video-encoder-config.https.any.js
@@ -90,6 +90,14 @@ const validButUnsupportedConfigs = [
},
},
{
+ comment: 'VP8 codec string not accepted by Web Codecs',
+ config: {
+ codec: 'vp08.00.10.08',
+ width: 640,
+ height: 480,
+ },
+ },
+ {
comment: 'Codec with bad casing',
config: {
codec: 'vP8',