WebCodecs API

repository·main·Indexed 22 days ago

https://github.com/w3c/webcodecs

A low-level API providing direct access to audio and video codecs for encoding and decoding. WebCodecs enables high-performance applications such as live streaming, cloud gaming, and media transcoding by leveraging native browser implementations. It features core interfaces like AudioEncoder, VideoEncoder, AudioDecoder, and VideoDecoder, and integrates with MediaStreamTrackProcessor to process live media tracks.

Tokens
4.5K
Snippets
5
Records
24
Agent score
79%

What's inside WebCodecs

  1. Overview of the WebCodecs API

    main

    The WebCodecs API provides low-level access to media codecs, allowing web applications to encode and decode audio and video directly. Unlike high-level APIs like HTMLMediaElement, MediaRecorder, or WebRTC which use codecs internally with fixed configurations, WebCodecs allows for flexible configuration of media codecs. This is particularly useful for high-performance applications such as:

    • Live streaming
    • Cloud gaming
    • Media file editing and transcoding

    Using WebCodecs is more efficient than implementing codecs in JavaScript or WebAssembly because it leverages the browser's native, optimized implementations, reducing bandwidth, improving performance, and increasing power efficiency.

  2. WebCodecs use cases and examples

    main

    WebCodecs is designed for high-performance media tasks that require direct access to encoded and decoded data. Key use cases include:

    • Low-latency video rendering: Rendering video frames directly to a <canvas> for applications like cloud gaming.
    • Live streaming upload: Using encoders to process live media for streaming.
    • Transcoding and offline processing: Performing encode/decode operations for media conversion.
    • Real-time communication (RTC): Handling media streams in real-time applications.
  3. Key use-cases for WebCodecs

    main

    WebCodecs is designed for high-performance media tasks that require more control than HTMLMediaElement, MediaRecorder, or WebRTC provide. Common use-cases include:

    • Low Latency: Extremely low latency live streaming (< 3s delay) and cloud gaming.
    • Live Streaming: Live stream uploading.
    • Media Processing: Non-realtime encoding, decoding, or transcoding (e.g., for local file editing).
    • Advanced RTC: Real-time communications requiring end-to-end encryption, control over buffer behavior, or spatial/temporal scalability.
    • Image Manipulation: Decoded and encoding images.
    • Stream Merging: Re-encoding multiple input media streams into a single encoded stream.
  4. Core interfaces and workflow in WebCodecs

    main

    WebCodecs provides a symmetric API for encoding and decoding media using specialized interfaces. The workflow involves transforming raw frames into encoded chunks (encoding) or transforming encoded chunks back into raw frames (decoding).

    Encoding Workflow

    1. Input: Provide AudioFrame or VideoFrame objects to an encoder.
    2. Process: Use AudioEncoder or VideoEncoder to process the frames.
    3. Output: The encoder produces EncodedAudioChunks or EncodedVideoChunks containing codec-specific bytes.

    Decoding Workflow

    1. Input: Provide EncodedAudioChunks or EncodedVideoChunks to a decoder.
    2. Process: Use AudioDecoder or VideoDecoder to process the chunks.
    3. Output: The decoder produces AudioFrame or VideoFrame objects.

    Data Types

    • AudioFrame: Contains decoded audio data. Can provide an AudioBuffer for rendering via AudioWorklet.
    • VideoFrame: Contains decoded video data. Can provide an ImageBitmap for manipulation in WebGL or rendering to a <canvas>.
  5. Understand WebCodecs registries

    main

    The WebCodecs ecosystem uses registries to manage codec identification and metadata:

    • WebCodecs Codec Registry: Used to identify and avoid collisions among codec strings and to define codec-specific members of WebCodecs codec configuration dictionaries. You can view the comprehensive list at the WebCodecs Codec Registry.
    • WebCodecs VideoFrame Metadata Registry: Enumerates the metadata fields that can be attached to VideoFrame objects using the VideoFrameMetadata dictionary. The full list is available at the WebCodecs VideoFrame Metadata Registry.
  6. Codec configuration and capabilities

    main

    WebCodecs allows for highly configurable codec implementations.

    Key behaviors:

    • Reconfiguration: A codec can be reconfigured at any time using .configure() as long as the state is not "closed". Chunks/Frames passed to .decode() or .encode() will use the settings from the most recent successful .configure() call.
    • Feature Detection: Because support for specific configuration parameters is implementation-specific, you should use the static isConfigSupported() methods to check if a specific configuration is valid before attempting to use it.
    • Parameters: Configuration includes standard WebCodecs parameters and codec-specific parameters defined in the WebCodecs Codec Registry.
  7. How WebCodecs compares to Media Source Extensions (MSE)

    main

    While MSE is widely used for low-latency streaming, WebCodecs is designed to address several limitations of the MSE model:

    • Low-latency control: MSE's low-latency mode is often implicit and lacks standardization across browsers, whereas WebCodecs provides direct control.
    • Buffer management: MSE requires applications to work around default 'stop on underrun' behaviors and requires manual containerization of input before buffering.
    • Seeking/History: For use cases like cloud gaming that require no history for seeking, MSE requires manual workarounds to disable history, while WebCodecs allows for more direct control.
    • Access to decoded data: MSE is primarily designed for rendering; WebCodecs provides easy access to decoded output, enabling use cases like transcoding.
    • Encoding: MSE only addresses the decoding side; WebCodecs provides both encoding and decoding capabilities.
  8. WebCodecs API design vs WhatWG Streams

    main

    WebCodecs defines Encoders and Decoders as standalone interfaces rather than native TransformStreams.

    While codecs are conceptually transformers (mapping a stream of inputs to a stream of outputs), implementing codec-specific controls like configure, flush, and reset directly on top of the WhatWG Streams API resulted in excessive complexity. Instead, WebCodecs provides dedicated codec interfaces, and developers are encouraged to wrap these interfaces in Streams manually if that model is preferred for their application architecture.

  9. Explore WebCodecs samples

    main

    You can interact with and test WebCodecs implementations by visiting the official WebCodecs samples website.

    Note on Browser Compatibility: To ensure all features and the latest API changes work correctly, it is recommended to use the latest version of Chrome Canary, as some recent API updates may not yet be available in Chrome Stable.

    https://webcodecs-samples.netlify.app/
  10. Encode media tracks for live streaming upload

    main

    To upload live audio and video, convert MediaStreamTrack objects into ReadableStreams of unencoded media using MediaStreamTrackProcessor. Then, feed these streams into AudioEncoder and VideoEncoder instances.

    Workflow:

    1. Use MediaStreamTrackProcessor(track).readable to get a stream of raw frames.
    2. Configure encoders with a specific codec and tuning parameters (like bitrate, framerate, width, and height).
    3. The output callback of the encoder receives byte arrays (encoded chunks) which are not in a container (like MP4); your application is responsible for muxing/containerizing these chunks before transmission.
    4. Use a loop or stream reader to continuously call encoder.encode(frame).
    // The tracks are converted to ReadableStreams of unencoded audio and video.
    const audio = (new MediaStreamTrackProcessor(audioTrack)).readable;
    const video = (new MediaStreamTrackProcessor(videoTrack)).readable;
    
    // Build and configure the encoders.
    const audioEncoder = new AudioEncoder({
      output: muxAndSend,
      error: onEncoderError,
    });
    const audioPromise = audioEncoder.configure({
      codec: 'opus',
      tuning: {
        bitrate: 60_000,
      }
    });
    
    const videoEncoder = new VideoEncoder({
      output: muxAndSend,
      error: onEncoderError,
    });
    const videoPromise = videoEncoder.configure({
      codec : 'vp8',
      tuning: {
        bitrate: 1_000_000,
        framerate: 24,
        width: 1024,
        height: 768
      }
    });
    
    try {
      await Promise.all([audioPromise, videoPromise]);
    } catch (exception) {
      // Configuration not supported.
      return;
    }
    
    // Helper to feed raw media to encoders as fast as possible.
    function readAndEncode(reader, encoder) {
      reader.read().then((result) => {
        if (result.done) return;
        encoder.encode(result.value);
        readAndEncode(reader, encoder);
      });
    }
    
    // Feed the encoders data from the track readers.
    readAndEncode(audio.getReader(), audioEncoder);
    readAndEncode(video.getReader(), videoEncoder);
  11. Render video frames to Canvas for low-latency streaming

    main

    To achieve extremely low latency (e.g., for cloud gaming), you can decode video chunks and paint the resulting VideoFrame objects directly to a <canvas> element.

    Key requirements:

    • Use VideoDecoder with an output callback that handles the VideoFrame.
    • VideoFrame is a CanvasImageSource, so you can use canvasContext.drawImage(frame, 0, 0).
    • IMPORTANT: You must call frame.close() immediately after painting to release the frame and avoid stalling the decoder.
    • Monitor decoder backpressure to ensure the application keeps up with the stream.
    // The document contains a canvas for displaying VideoFrames.
    const canvasElement = document.getElementById("canvas");
    const canvasContext = canvas.getContext('2d', canvasOptions)
    
    // Paint every video frame ASAP for lowest latency.
    function paintFrameToCanvas(videoFrame) {
      // VideoFrame is a CanvasImageSource.
      canvasContext.drawImage(videoFrame, 0, 0);
    
      // IMPORTANT: Release the frame to avoid stalling the decoder.
      videoFrame.close();
    }
    
    const videoDecoder = new VideoDecoder({
      output: paintFrameToCanvas,
      error: onDecoderError
    });
    
    videoDecoder.configure({codec: 'vp8'}).then(() => {
      // The app fetches VP8 chunks, feeding each chunk to the decode
      // callback as fast as possible.
      streamEncodedChunks(videoDecoder.decode.bind(videoDecoder));
    }).catch(() => {
      // App provides fallback logic when config not supported.
      ...
    });