WPT (Web Platform Tests) Status

January 24, 2026 · View on GitHub

This directory contains tests ported from the W3C Web Platform Tests for WebCodecs API compliance.

Test Summary

StatusCount
Passing608
Skipped6
Failing0
Total614

Test Files Overview

VideoFrame Tests

FileTestsStatusNotes
video-frame-wpt.spec.ts116 passingCompleteAll pixel formats, format conversion, security (WPT)
video-frame-orientation.spec.ts6 passingCompleteRotation, flip properties and combinations

Format Conversion (WPT videoFrame-copyTo-rgb.any.js):

Source FormatTarget FormatResult
I420, I422, I444, NV12, NV21RGBA, RGBX, BGRA, BGRX✅ Success
RGBA, RGBX, BGRA, BGRXRGBA, RGBX, BGRA, BGRX✅ Success
RGBA, RGBX, BGRA, BGRXI420, I422, I444, NV12❌ NotSupportedError

Security Tests (overflow and rect validation):

Test CaseExpectedStatus
Layout offset overflow (2³²-2)TypeError✅ Pass
Layout stride × height overflowTypeError✅ Pass
Rect alignment with format conversionValidates source format✅ Pass

Supported Pixel Formats:

  • 8-bit YUV: I420, I420A, I422, I422A, I444, I444A, NV12, NV21
  • 10-bit YUV: I420P10, I420AP10, I422P10, I422AP10, I444P10, I444AP10
  • 12-bit YUV: I420P12, I422P12, I444P12
  • RGB: RGBA, RGBX, BGRA, BGRX

AudioData Tests

FileTestsStatusNotes
audio-data-wpt.spec.ts38 passingCompleteAll formats supported

Supported Audio Formats:

  • Interleaved: u8, s16, s32, f32
  • Planar: u8-planar, s16-planar, s32-planar, f32-planar

Encoded Chunk Tests

FileTestsStatusNotes
encoded-chunk-wpt.spec.ts20 passingCompleteEncodedVideoChunk, EncodedAudioChunk

ImageDecoder Tests

FileTestsStatusNotes
image-decoder-wpt.spec.ts15 passingCompletePNG, JPEG, GIF, WebP, AVIF
image-decoder.spec.ts21 passingCompleteOptions: desiredWidth/Height, preferAnimation, colorSpaceConversion

VideoEncoder Tests

FileTestsStatusNotes
video-encoder-behavior.spec.ts25 passingCompleteEncode, flush, reset, callbacks
video-encoder-config.spec.ts42 passingCompleteisConfigSupported, configure
video-encoder-orientation.spec.ts4 passing, 1 skippedCompleteRotation, flip in encoded output
video-encoder-content-hint.spec.ts7 passingCompletecontentHint config preservation
per-frame-qp-encoding.spec.ts13 passingCompletebitrateMode: 'quantizer', codec QP

Supported Video Codecs (Encoding):

  • AV1 (av01.x.xxM.xx)
  • VP8 (vp8)
  • VP9 (vp09.xx.xx.xx)
  • H.264 (avc1.xxxxxx) - AVC and Annex B formats
  • H.265 (hvc1.x.x.Lxxx.xx, hev1.x.x.Lxxx.xx) - HEVC and Annex B formats

VideoDecoder Tests

FileTestsStatusNotes
video-decoder-behavior.spec.ts16 passingCompleteDecode, flush, reset, callbacks
video-decoder-config.spec.ts17 passingCompleteisConfigSupported, configure
codec-specific-decoder.spec.ts24 passingCompleteH.264, VP8, VP9, AV1, SEI, interlaced

AudioEncoder Tests

FileTestsStatusNotes
audio-encoder-behavior.spec.ts10 passingCompleteEncode, flush, callbacks
audio-encoder-config.spec.ts18 passingCompleteisConfigSupported, configure

Supported Audio Codecs (Encoding):

  • AAC (mp4a.40.2)
  • Opus (opus)
  • MP3 (mp3)
  • FLAC (flac)

AudioDecoder Tests

FileTestsStatusNotes
audio-decoder-behavior.spec.ts12 passingCompleteDecode, flush, callbacks
audio-decoder-config.spec.ts18 passingCompleteisConfigSupported, configure

VideoColorSpace Tests

FileTestsStatusNotes
video-color-space.spec.ts19 passingCompleteConstructor, toJSON

Full Cycle Tests (Encode/Decode Roundtrip)

FileTestsStatusNotes
full-cycle-test.spec.ts19 passing, 5 skippedCompleteAll codecs work

Test Variants:

  • Basic encoding and decoding
  • Realtime latency mode
  • Stripped color space (test bitstream-embedded color space)

Skipped Tests:

  • Rate control tests (dynamic bitrate reconfiguration) - covered by reconfiguring-encoder.spec.ts

Encoder Reconfiguration Tests

FileTestsStatusNotes
reconfiguring-encoder.spec.ts6 passingCompleteAll codecs

Tests dynamic encoder reconfiguration with:

  • Resolution changes (800x600 → 640x480 → 800x600)
  • Bitrate changes

Supported Codecs:

  • AV1, VP8, VP9 (Profile 0 & 2), H.264 (AVC & Annex B)

Temporal SVC Encoding Tests

FileTestsStatusNotes
temporal-svc-encoding.spec.ts8 passingPassingL1Tx temporal layer metadata implemented

Implementation:

  • scalabilityMode L1Tx modes populate metadata.svc.temporalLayerId
  • Temporal layer ID computed from output frame pattern per W3C spec
  • L1T2: [0, 1, 0, 1, ...], L1T3: [0, 2, 1, 2, 0, 2, 1, 2, ...]
  • Multi-spatial modes (L2T*, S*) not yet supported

Skipped WPT Assertions:

The following assertions from the original WPT are skipped because our implementation only computes temporal layer metadata. FFmpeg is NOT configured for actual SVC encoding, so base layer frames cannot be decoded independently:

// WPT: assert_equals(frames_decoded, base_layer_frames);
// WPT: assert_equals(corrupted_frames.length, 0, `corrupted_frames: ${corrupted_frames}`);

See: src/webcodecs/video_encoder.rs - temporal layer ID computed from frame pattern, not FFmpeg SVC


Missing WPT Tests (Not Ported)

Browser-Specific (Cannot Port)

These tests require browser APIs not available in Node.js:

  • video-frame-serialization.any.js - MessageChannel transfer
  • audio-data-serialization.any.js - MessageChannel transfer
  • chunk-serialization.any.js - Serialization
  • videoFrame-texImage.any.js - WebGL textures
  • videoFrame-createImageBitmap.any.js - ImageBitmap
  • videoFrame-drawImage.any.js - Canvas drawing
  • *.crossOriginIsolated.* - COOP/COEP tests
  • *.crossAgentCluster.* - Cross-agent tests
  • idlharness.https.any.js - WebIDL validation

Orientation Tests

VideoFrame rotation and flip properties are fully implemented:

  • videoFrame-orientation.any.jsvideo-frame-orientation.spec.ts
  • video-encoder-orientation.https.any.jsvideo-encoder-orientation.spec.ts
  • videoDecoder-codec-specific-orientation.https.any.js - Decoder orientation not yet ported

Per-Frame QP and Content Hint Tests

  • per-frame-qp-encoding.https.any.jsper-frame-qp-encoding.spec.ts
  • video-encoder-content-hint.https.any.jsvideo-encoder-content-hint.spec.ts

H.264 Specific Tests

  • videoDecoder-h264-sei.https.any.jscodec-specific-decoder.spec.ts
  • videoDecoder-interlaced-h264.https.any.jscodec-specific-decoder.spec.ts

Other Missing Tests

  • transfering.https.any.js - Transfer ownership (browser-only, partially applicable)

Known Implementation Gaps

Alpha Plane Extraction (8-bit)

FormatBit DepthStatus
I422A8-bit + alphaPlane extraction issue
I444A8-bit + alphaPlane extraction issue

Temporal SVC

  • L1Tx modes (L1T2, L1T3) populate metadata.svc.temporalLayerId
  • Multi-spatial modes (L2T*, S2T*, etc.) not yet supported

Running Tests

# Run all WPT tests
pnpm test --match='*wpt*'

# Run specific test file
npx ava __test__/wpt/video-frame-wpt.spec.ts --verbose

# Run tests matching pattern
npx ava __test__/wpt/*.spec.ts --match='*VideoEncoder*'

Implementation Differences from Browser WPT

This section documents intentional deviations from browser-based W3C Web Platform Tests behavior due to Node.js/FFmpeg implementation characteristics.

AudioEncoder Error Handling Timing

Tests affected: audio-encoder-behavior.spec.ts - channel number variation, sample rate variation

W3C WPT expectation:

encoder.encode(bad_data)
await promise_rejects_dom(t, 'EncodingError', encoder.flush())

The spec expects flush() to reject with EncodingError when encoding fails.

Our implementation: Due to FFmpeg worker thread timing differences, the error callback may fire and close the encoder before flush() can reject with the proper error. When this happens, flush() throws InvalidStateError: Cannot flush a closed codec instead of EncodingError.

Test adaptation:

encoder.encode(badData)
await new Promise((resolve) => setTimeout(resolve, 50)) // Allow error callback to fire

if (encoder.state === 'closed') {
  // Error callback already closed the encoder - verify error was received
  t.is(errorCount, 1)
} else {
  // Encoder still open - flush should throw
  await t.throwsAsync(encoder.flush(), {
    message: /EncodingError|InvalidStateError/,
  })
}

Core behaviors still verified:

  • Error callback fires correctly with encoding error
  • Encoder enters closed state after error
  • Invalid data (mismatched channels/sample rate) is rejected

AudioDecoder Configuration Error Timing

Tests affected: audio-decoder.spec.ts - FLAC codec requires description

Issue: The decoder state transitions to closed before the error callback fires via ThreadsafeFunction.

Test adaptation:

// Wait for BOTH decoder to close AND error callback to fire
while ((decoder.state !== 'closed' || errors.length === 0) && elapsed < maxWait) {
  await new Promise((resolve) => setTimeout(resolve, pollInterval))
  elapsed += pollInterval
}

Contributing

When adding new WPT ports:

  1. Follow the existing naming convention: {feature}-wpt.spec.ts or {feature}-{aspect}.spec.ts
  2. Use test.skip() for tests that require unimplemented features
  3. Add appropriate comments explaining why tests are skipped
  4. Document any implementation-specific timing differences in this README
  5. Update this README with the new test status