> ## Documentation Index
> Fetch the complete documentation index at: https://docs.node-webcodecs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# VideoEncoder

> Encode VideoFrame objects into EncodedVideoChunk for H.264, VP8, VP9, and AV1

# 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.

<Info>
  This class implements the [W3C WebCodecs VideoEncoder specification](https://w3c.github.io/webcodecs/#videoencoder). Hardware acceleration is available via platform-specific encoders (VideoToolbox on macOS, NVENC on NVIDIA GPUs, QuickSync on Intel).
</Info>

## Quick Example

```typescript theme={null}
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:

```typescript theme={null}
// 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

| Codec | WebCodecs String  | Hardware Options                  |
| ----- | ----------------- | --------------------------------- |
| H.264 | `avc1.42E01E`     | `h264_videotoolbox`, `h264_nvenc` |
| H.265 | `hvc1.1.6.L93.B0` | `hevc_videotoolbox`, `hevc_nvenc` |
| VP8   | `vp8`             | -                                 |
| VP9   | `vp09.00.10.08`   | -                                 |
| AV1   | `av01.0.04M.08`   | -                                 |

***

## Constructor

Creates a new `VideoEncoder` with output and error callbacks.

```typescript theme={null}
new VideoEncoder(init: VideoEncoderInit)
```

<ParamField body="init" type="VideoEncoderInit" required>
  Initialization callbacks for handling encoded output and errors.

  <Expandable title="VideoEncoderInit properties">
    <ParamField body="output" type="(chunk: EncodedVideoChunk, metadata?: VideoEncoderOutputMetadata) => void" required>
      Callback invoked for each encoded chunk. The first keyframe includes `decoderConfig` in metadata.
    </ParamField>

    <ParamField body="error" type="(error: DOMException) => void" required>
      Callback invoked when an encoding error occurs.
    </ParamField>
  </Expandable>
</ParamField>

**Throws:** `TypeError` if callbacks are not functions.

<Accordion title="Example: Creating an encoder">
  ```typescript theme={null}
  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);
    }
  });
  ```
</Accordion>

***

## Properties

<ResponseField name="state" type="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
</ResponseField>

<ResponseField name="encodeQueueSize" type="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.
</ResponseField>

***

## Methods

### isConfigSupported()

Static method to check if a configuration is supported before creating an encoder.

```typescript theme={null}
static VideoEncoder.isConfigSupported(config: VideoEncoderConfig): Promise<VideoEncoderSupport>
```

<ParamField body="config" type="VideoEncoderConfig" required>
  Configuration to test for support.
</ParamField>

**Returns:** `Promise<VideoEncoderSupport>` with `supported` boolean and normalized `config`.

<Accordion title="Example: Checking codec support">
  ```typescript theme={null}
  // 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';
  ```
</Accordion>

***

### configure()

Configures the encoder with codec parameters. Must be called before encoding frames.

```typescript theme={null}
encoder.configure(config: VideoEncoderConfig): void
```

<ParamField body="config" type="VideoEncoderConfig" required>
  Encoder configuration specifying codec, dimensions, bitrate, and other parameters.

  <Expandable title="VideoEncoderConfig properties">
    <ParamField body="codec" type="string" required>
      Codec identifier. Use WebCodecs MIME types (e.g., `'avc1.42E01E'`) or FFmpeg codec names (e.g., `'h264_videotoolbox'`).
    </ParamField>

    <ParamField body="width" type="number" required>
      Frame width in pixels. Must be greater than 0.
    </ParamField>

    <ParamField body="height" type="number" required>
      Frame height in pixels. Must be greater than 0.
    </ParamField>

    <ParamField body="displayWidth" type="number">
      Display width for pixel aspect ratio correction. Defaults to `width`.
    </ParamField>

    <ParamField body="displayHeight" type="number">
      Display height for pixel aspect ratio correction. Defaults to `height`.
    </ParamField>

    <ParamField body="bitrate" type="number">
      Target bitrate in bits per second. Example: `5_000_000` for 5 Mbps.
    </ParamField>

    <ParamField body="framerate" type="number">
      Target framerate in frames per second. Defaults to `30`.
    </ParamField>

    <ParamField body="hardwareAcceleration" type="HardwareAcceleration">
      Hardware acceleration preference:

      * `'no-preference'` - Let encoder decide (default)
      * `'prefer-hardware'` - Use hardware if available
      * `'prefer-software'` - Force software encoding
    </ParamField>

    <ParamField body="latencyMode" type="LatencyMode">
      Encoding latency optimization:

      * `'quality'` - Optimize for compression ratio (default)
      * `'realtime'` - Optimize for low latency
    </ParamField>

    <ParamField body="bitrateMode" type="BitrateMode">
      Bitrate control mode:

      * `'constant'` - Constant bitrate (CBR)
      * `'variable'` - Variable bitrate (VBR)
      * `'quantizer'` - Constant quality (CQP)
    </ParamField>

    <ParamField body="alpha" type="AlphaOption">
      Alpha channel handling:

      * `'discard'` - Remove alpha channel
      * `'keep'` - Preserve alpha (if codec supports it)
    </ParamField>

    <ParamField body="scalabilityMode" type="string">
      SVC/temporal layering mode. Example: `'L1T2'` for 1 spatial layer, 2 temporal layers.
    </ParamField>

    <ParamField body="colorSpace" type="VideoColorSpaceInit">
      Color space metadata including `primaries`, `transfer`, `matrix`, and `fullRange`.
    </ParamField>

    <ParamField body="avc" type="object">
      H.264-specific options.

      <Expandable title="avc properties">
        <ParamField body="format" type="'annexb' | 'avc'">
          Output format:

          * `'annexb'` - Annex B format with start codes (default)
          * `'avc'` - AVC format with length-prefixed NALUs
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="useWorkerThread" type="boolean">
      Use async encoding via worker thread. Defaults to `true`. Set to `false` for synchronous encoding (blocks event loop).
    </ParamField>
  </Expandable>
</ParamField>

**Throws:**

* `DOMException` if encoder is closed
* `DOMException` if codec is not supported
* `DOMException` if dimensions are invalid

<Accordion title="Example: Basic configuration">
  ```typescript theme={null}
  encoder.configure({
    codec: 'avc1.42E01E',
    width: 1920,
    height: 1080,
    bitrate: 5_000_000,
    framerate: 30
  });
  ```
</Accordion>

<Accordion title="Example: HDR encoding with VP9">
  ```typescript theme={null}
  encoder.configure({
    codec: 'vp09.00.10.08',
    width: 3840,
    height: 2160,
    bitrate: 20_000_000,
    colorSpace: {
      primaries: 'bt2020',
      transfer: 'pq',
      matrix: 'bt2020-ncl'
    }
  });
  ```
</Accordion>

***

### encode()

Encodes a video frame. The frame is queued for encoding and the output callback is invoked when complete.

```typescript theme={null}
encoder.encode(frame: VideoFrame, options?: VideoEncoderEncodeOptions): void
```

<ParamField body="frame" type="VideoFrame" required>
  The `VideoFrame` to encode.
</ParamField>

<ParamField body="options" type="VideoEncoderEncodeOptions">
  Optional encoding parameters.

  <Expandable title="VideoEncoderEncodeOptions properties">
    <ParamField body="keyFrame" type="boolean">
      Force this frame to be a keyframe (I-frame). Keyframes are independently decodable.
      Defaults to `false`.
    </ParamField>
  </Expandable>
</ParamField>

**Throws:**

* `DOMException` if encoder is not configured
* `DOMException` if frame is invalid or closed

<Warning>
  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.
</Warning>

<Accordion title="Example: Encoding with keyframe control">
  ```typescript theme={null}
  // 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
  }
  ```
</Accordion>

***

### flush()

Waits for all pending encode operations to complete.

```typescript theme={null}
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

<Accordion title="Example: Flushing before close">
  ```typescript theme={null}
  // 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();
  ```
</Accordion>

***

### reset()

Resets the encoder to unconfigured state, aborting any pending operations.

```typescript theme={null}
encoder.reset(): void
```

**Throws:** `DOMException` if encoder is closed.

<Accordion title="Example: Reconfiguring encoder">
  ```typescript theme={null}
  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();
  ```
</Accordion>

***

### close()

Closes the encoder and releases all resources. The encoder cannot be used after calling `close()`.

```typescript theme={null}
encoder.close(): void
```

<Accordion title="Example: Proper cleanup">
  ```typescript theme={null}
  try {
    for (const frame of frames) {
      encoder.encode(frame);
      frame.close();
    }
    await encoder.flush();
  } finally {
    encoder.close();  // Always close to release resources
  }
  ```
</Accordion>

***

### addEventListener()

Adds an event listener for encoder events.

```typescript theme={null}
encoder.addEventListener(type: string, listener: () => void, options?: { once?: boolean }): void
```

<ParamField body="type" type="string" required>
  Event type. Currently only `'dequeue'` is supported.
</ParamField>

<ParamField body="listener" type="() => void" required>
  Callback to invoke when the event fires.
</ParamField>

<ParamField body="options" type="object">
  <Expandable title="options properties">
    <ParamField body="once" type="boolean">
      If `true`, the listener is removed after being invoked once.
    </ParamField>
  </Expandable>
</ParamField>

***

### removeEventListener()

Removes an event listener.

```typescript theme={null}
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:

```typescript theme={null}
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();
}
```

<Info>
  The `dequeue` event fires whenever a frame completes encoding, reducing `encodeQueueSize`. This allows you to throttle input to prevent unbounded memory growth.
</Info>

***

## Interfaces

### VideoEncoderConfig

Configuration options for the encoder.

```typescript theme={null}
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.

```typescript theme={null}
interface VideoEncoderInit {
  output: (chunk: EncodedVideoChunk, metadata?: VideoEncoderOutputMetadata) => void;
  error: (error: DOMException) => void;
}
```

### VideoEncoderOutputMetadata

Metadata returned with encoded chunks.

```typescript theme={null}
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.

```typescript theme={null}
interface VideoEncoderEncodeOptions {
  keyFrame?: boolean;  // Force keyframe (default: false)
}
```

### VideoEncoderSupport

Result from `isConfigSupported()`.

```typescript theme={null}
interface VideoEncoderSupport {
  supported: boolean;
  config: VideoEncoderConfig;
}
```

***

## Type Aliases

### LatencyMode

```typescript theme={null}
type LatencyMode = 'quality' | 'realtime';
```

| Value        | Description                                        |
| ------------ | -------------------------------------------------- |
| `'quality'`  | Optimize for compression ratio (may buffer frames) |
| `'realtime'` | Optimize for low latency encoding                  |

### BitrateMode

```typescript theme={null}
type BitrateMode = 'constant' | 'variable' | 'quantizer';
```

| Value         | Description                                        |
| ------------- | -------------------------------------------------- |
| `'constant'`  | Constant bitrate (CBR) - consistent file size      |
| `'variable'`  | Variable bitrate (VBR) - better quality/size ratio |
| `'quantizer'` | Constant quality (CQP) - consistent visual quality |

### AlphaOption

```typescript theme={null}
type AlphaOption = 'discard' | 'keep';
```

| Value       | Description                                              |
| ----------- | -------------------------------------------------------- |
| `'discard'` | Remove alpha channel from output                         |
| `'keep'`    | Preserve alpha channel (codec must support transparency) |

***

## See Also

<CardGroup cols={2}>
  <Card title="VideoFrame" icon="image" href="/api-reference/VideoFrame">
    Raw video frame data for encoding
  </Card>

  <Card title="VideoDecoder" icon="film" href="/api-reference/VideoDecoder">
    Decodes EncodedVideoChunks back to VideoFrames
  </Card>

  <Card title="EncodedVideoChunk" icon="box" href="/api-reference/EncodedVideoChunk">
    Compressed video data output from encoder
  </Card>

  <Card title="Hardware Acceleration Guide" icon="bolt" href="/guides/hardware-acceleration">
    Platform-specific hardware encoding setup
  </Card>
</CardGroup>
