Client-side video conversion package used by @wordpress/upload-media. It currently converts animated GIFs to MP4/WebM during media upload.
This package is not used directly. When an animated GIF is uploaded, its frames are decoded using the browser’s native ImageDecoder API and re-encoded via WebCodecs (VideoEncoder) using the mediabunny library as an internal implementation detail. All processing runs inside a Web Worker to keep the main thread responsive.
Installation
Install the module:
npm install @wordpress/video-conversion --save
Requirements
- WebCodecs support: the browser must expose
ImageDecoderandVideoEncoder(available in Chromium-based browsers and Safari 16.4+). - Web Workers support: the browser must support Web Workers.
API Reference
cancelOperations
Cancels all ongoing operations for a given item ID.
Cancellation takes effect at async boundaries (waiting for the lock, encoder-support check, decoder completion, between frames).
Parameters
- id
ItemId: Item ID.
Returns
Promise< boolean >: Whether an operation was cancelled.
convertGifToVideo
Converts an animated GIF to a video file (MP4 or WebM).
Decodes GIF frames via the browser ImageDecoder (honoring per-frame delays) and re-encodes them with mediabunny / WebCodecs.
Accepts the GIF as a Blob so the bytes are read once, here in the worker, instead of being materialized on the main thread and transferred. An ArrayBuffer is still accepted for direct callers and tests.
Parameters
- id
ItemId: Item ID. - gifSource
ArrayBuffer | Blob: GIF file as a Blob/File or ArrayBuffer. - outputMimeType
string: Output MIME type (‘video/mp4’ or ‘video/webm’). - maxDimensions
number: Optional maximum dimension for downscaling. - maxTotalPixels
number: Optional budget for total decoded pixels (width × height × frame count) beyond which the conversion is rejected with SIZE_LIMIT_ERROR_PREFIX. Defaults to DEFAULT_MAX_TOTAL_PIXELS;0disables.
Returns
Promise< ArrayBuffer >: Encoded video buffer.
DEFAULT_MAX_TOTAL_PIXELS
Default budget for total decoded pixels (width × height × frame count) beyond which conversion is not attempted.
Conversion cost is roughly proportional to the total number of decoded pixels. 300 megapixels approximates what a mid-range machine converts within the ~30s the caller is willing to wait (e.g. a 1920×1080 GIF at ~145 frames); anything larger would likely be abandoned anyway, so it is cheaper to not start. Pass 0 to disable the check.
SIZE_LIMIT_ERROR_PREFIX
Message prefix for GIFs skipped because they exceed the total-pixel budget.
Starts with UNSUPPORTED_ERROR_PREFIX so existing consumers treat the skip as a graceful fallback (keep the uploaded GIF, no companion video); the longer prefix lets consumers distinguish it, e.g. to log a warning. Like UNSUPPORTED_ERROR_PREFIX, the contract is the message prefix because only the message string survives the worker boundary.
UNSUPPORTED_ERROR_PREFIX
Message prefix for “unsupported but graceful” outcomes (no WebCodecs, unsupported codec). Consumers detect this prefix and fall back to uploading the original GIF instead of surfacing a hard error.
The contract is the message prefix, not the Error type: the worker RPC layer (comctx) serializes a thrown error to its message string only – the Error subclass, name, and stack do not survive the worker boundary.