Skip to main content

VideoEncoder

The VideoEncoder class encodes raw VideoFrame objects into compressed EncodedVideoChunk objects. It supports multiple codecs including H.264, H.265/HEVC, VP8, VP9, and AV1, with optional hardware acceleration.
This class implements the W3C WebCodecs VideoEncoder specification. Hardware acceleration is available via platform-specific encoders (VideoToolbox on macOS, NVENC on NVIDIA GPUs, QuickSync on Intel).

Quick Example

import { VideoEncoder, VideoFrame } from 'node-webcodecs';

// Create encoder with output callback
const encoder = new VideoEncoder({
  output: (chunk, metadata) => {
    console.log(`Encoded ${chunk.type} frame: ${chunk.byteLength} bytes`);

    // Save decoder config on first keyframe
    if (metadata?.decoderConfig) {
      console.log('Codec:', metadata.decoderConfig.codec);
    }
  },
  error: (err) => console.error('Encoding error:', err)
});

// Configure for H.264 at 1080p
encoder.configure({
  codec: 'avc1.42E01E',
  width: 1920,
  height: 1080,
  bitrate: 5_000_000,
  framerate: 30
});

// Encode frames
const frame = new VideoFrame(rgbaBuffer, {
  format: 'RGBA',
  codedWidth: 1920,
  codedHeight: 1080,
  timestamp: 0
});

encoder.encode(frame);
frame.close();  // Always close frames after encoding!

await encoder.flush();
encoder.close();

Hardware Acceleration Example

Use platform-specific codec names for hardware-accelerated encoding:
// Check for hardware encoder support
const hwSupport = await VideoEncoder.isConfigSupported({
  codec: 'h264_videotoolbox',  // macOS VideoToolbox
  width: 1920,
  height: 1080,
  hardwareAcceleration: 'prefer-hardware'
});

if (hwSupport.supported) {
  encoder.configure({
    codec: 'h264_videotoolbox',
    width: 1920,
    height: 1080,
    bitrate: 10_000_000
  });
} else {
  // Fallback to software encoder
  encoder.configure({
    codec: 'avc1.42E01E',
    width: 1920,
    height: 1080,
    bitrate: 10_000_000
  });
}

Codec Reference

CodecWebCodecs StringHardware Options
H.264avc1.42E01Eh264_videotoolbox, h264_nvenc
H.265hvc1.1.6.L93.B0hevc_videotoolbox, hevc_nvenc
VP8vp8-
VP9vp09.00.10.08-
AV1av01.0.04M.08-

Constructor

Creates a new VideoEncoder with output and error callbacks.
new VideoEncoder(init: VideoEncoderInit)
init
VideoEncoderInit
required
Initialization callbacks for handling encoded output and errors.
Throws: TypeError if callbacks are not functions.
const chunks: EncodedVideoChunk[] = [];
let decoderConfig: VideoDecoderConfig | null = null;

const encoder = new VideoEncoder({
  output: (chunk, metadata) => {
    chunks.push(chunk);

    // Capture decoder config from first keyframe
    if (metadata?.decoderConfig) {
      decoderConfig = metadata.decoderConfig;
    }
  },
  error: (err) => {
    console.error('Encoding failed:', err.message);
  }
});

Properties

state
CodecState
required
Current encoder state. One of:
  • 'unconfigured' - Not yet configured, or reset() was called
  • 'configured' - Ready to encode frames
  • 'closed' - Encoder has been closed and cannot be used
encodeQueueSize
number
required
Number of pending encode operations in the queue. Useful for implementing backpressure to prevent memory exhaustion when encoding faster than output can be processed.

Methods

isConfigSupported()

Static method to check if a configuration is supported before creating an encoder.
static VideoEncoder.isConfigSupported(config: VideoEncoderConfig): Promise<VideoEncoderSupport>
config
VideoEncoderConfig
required
Configuration to test for support.
Returns: Promise<VideoEncoderSupport> with supported boolean and normalized config.
// Check software encoder support
const result = await VideoEncoder.isConfigSupported({
  codec: 'avc1.42E01E',
  width: 1920,
  height: 1080
});

if (result.supported) {
  console.log('H.264 encoding is supported');
}

// Check hardware encoder with fallback
const hwResult = await VideoEncoder.isConfigSupported({
  codec: 'h264_videotoolbox',
  width: 3840,
  height: 2160,
  hardwareAcceleration: 'prefer-hardware'
});

const codec = hwResult.supported ? 'h264_videotoolbox' : 'avc1.42E01E';

configure()

Configures the encoder with codec parameters. Must be called before encoding frames.
encoder.configure(config: VideoEncoderConfig): void
config
VideoEncoderConfig
required
Encoder configuration specifying codec, dimensions, bitrate, and other parameters.
Throws:
  • DOMException if encoder is closed
  • DOMException if codec is not supported
  • DOMException if dimensions are invalid
encoder.configure({
  codec: 'avc1.42E01E',
  width: 1920,
  height: 1080,
  bitrate: 5_000_000,
  framerate: 30
});
encoder.configure({
  codec: 'vp09.00.10.08',
  width: 3840,
  height: 2160,
  bitrate: 20_000_000,
  colorSpace: {
    primaries: 'bt2020',
    transfer: 'pq',
    matrix: 'bt2020-ncl'
  }
});

encode()

Encodes a video frame. The frame is queued for encoding and the output callback is invoked when complete.
encoder.encode(frame: VideoFrame, options?: VideoEncoderEncodeOptions): void
frame
VideoFrame
required
The VideoFrame to encode.
options
VideoEncoderEncodeOptions
Optional encoding parameters.
Throws:
  • DOMException if encoder is not configured
  • DOMException if frame is invalid or closed
Always call frame.close() after encoding to prevent memory leaks! The encoder takes a snapshot of the frame data, so the original frame can be closed immediately after encode() returns.
// Force keyframes at regular intervals (every 2 seconds at 30fps)
for (let i = 0; i < frames.length; i++) {
  const isKeyFrame = i % 60 === 0;  // Keyframe every 60 frames

  encoder.encode(frames[i], { keyFrame: isKeyFrame });
  frames[i].close();  // MUST close to prevent memory leak
}

flush()

Waits for all pending encode operations to complete.
encoder.flush(): Promise<void>
Returns: Promise<void> that resolves when all frames have been encoded. Throws:
  • DOMException if encoder is not configured
  • DOMException if an encoding error occurs
// Encode all frames
for (const frame of frames) {
  encoder.encode(frame);
  frame.close();
}

// Wait for all encodes to complete
await encoder.flush();

console.log('All frames encoded!');
encoder.close();

reset()

Resets the encoder to unconfigured state, aborting any pending operations.
encoder.reset(): void
Throws: DOMException if encoder is closed.
encoder.configure({ codec: 'avc1.42E01E', width: 1920, height: 1080 });
encoder.encode(frame1);
frame1.close();

// Abort and reconfigure with different settings
encoder.reset();

encoder.configure({ codec: 'vp09.00.10.08', width: 1280, height: 720 });
encoder.encode(frame2);
frame2.close();

close()

Closes the encoder and releases all resources. The encoder cannot be used after calling close().
encoder.close(): void
try {
  for (const frame of frames) {
    encoder.encode(frame);
    frame.close();
  }
  await encoder.flush();
} finally {
  encoder.close();  // Always close to release resources
}

addEventListener()

Adds an event listener for encoder events.
encoder.addEventListener(type: string, listener: () => void, options?: { once?: boolean }): void
type
string
required
Event type. Currently only 'dequeue' is supported.
listener
() => void
required
Callback to invoke when the event fires.
options
object

removeEventListener()

Removes an event listener.
encoder.removeEventListener(type: string, listener: () => void): void

Backpressure Management

When encoding video faster than it can be output (e.g., writing to disk), use encodeQueueSize and dequeue events to implement backpressure:
const MAX_QUEUE_SIZE = 10;

async function encodeWithBackpressure(frames: VideoFrame[]) {
  for (const frame of frames) {
    // Wait if queue is too large
    while (encoder.encodeQueueSize >= MAX_QUEUE_SIZE) {
      await new Promise<void>(resolve => {
        encoder.addEventListener('dequeue', resolve, { once: true });
      });
    }

    encoder.encode(frame);
    frame.close();
  }

  await encoder.flush();
}
The dequeue event fires whenever a frame completes encoding, reducing encodeQueueSize. This allows you to throttle input to prevent unbounded memory growth.

Interfaces

VideoEncoderConfig

Configuration options for the encoder.
interface VideoEncoderConfig {
  codec: string;                           // Required
  width: number;                           // Required
  height: number;                          // Required
  displayWidth?: number;
  displayHeight?: number;
  bitrate?: number;
  framerate?: number;
  hardwareAcceleration?: HardwareAcceleration;
  alpha?: AlphaOption;
  scalabilityMode?: string;
  bitrateMode?: BitrateMode;
  latencyMode?: LatencyMode;
  colorSpace?: VideoColorSpaceInit;
  avc?: { format?: 'annexb' | 'avc' };
  useWorkerThread?: boolean;
}

VideoEncoderInit

Callbacks for encoder initialization.
interface VideoEncoderInit {
  output: (chunk: EncodedVideoChunk, metadata?: VideoEncoderOutputMetadata) => void;
  error: (error: DOMException) => void;
}

VideoEncoderOutputMetadata

Metadata returned with encoded chunks.
interface VideoEncoderOutputMetadata {
  decoderConfig?: {
    codec: string;
    codedWidth: number;
    codedHeight: number;
    description?: ArrayBuffer;  // Codec extradata (SPS/PPS for H.264)
  };
  svc?: {
    temporalLayerId: number;    // 0 = base layer
  };
}

VideoEncoderEncodeOptions

Options for encoding a single frame.
interface VideoEncoderEncodeOptions {
  keyFrame?: boolean;  // Force keyframe (default: false)
}

VideoEncoderSupport

Result from isConfigSupported().
interface VideoEncoderSupport {
  supported: boolean;
  config: VideoEncoderConfig;
}

Type Aliases

LatencyMode

type LatencyMode = 'quality' | 'realtime';
ValueDescription
'quality'Optimize for compression ratio (may buffer frames)
'realtime'Optimize for low latency encoding

BitrateMode

type BitrateMode = 'constant' | 'variable' | 'quantizer';
ValueDescription
'constant'Constant bitrate (CBR) - consistent file size
'variable'Variable bitrate (VBR) - better quality/size ratio
'quantizer'Constant quality (CQP) - consistent visual quality

AlphaOption

type AlphaOption = 'discard' | 'keep';
ValueDescription
'discard'Remove alpha channel from output
'keep'Preserve alpha channel (codec must support transparency)

See Also