Helios supports a wide range of output formats and codecs through FFmpeg and WebCodecs, allowing you to optimize for quality, file size, or compatibility.
Video containers
MP4
Most widely supported container format:
const renderer = new Renderer({
videoCodec: 'libx264',
pixelFormat: 'yuv420p'
});
await renderer.render(url, './output.mp4');
Compatible codecs:
- H.264 (
libx264, h264_nvenc, h264_qsv, h264_videotoolbox)
- H.265 (
libx265, hevc_nvenc, hevc_qsv, hevc_videotoolbox)
- AV1 (
libaom-av1, libsvtav1)
WebM
Open source container for web delivery:
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
audioCodec: 'libvorbis'
});
await renderer.render(url, './output.webm');
Compatible codecs:
- VP8 (
libvpx)
- VP9 (
libvpx-vp9)
- AV1 (
libaom-av1)
MOV
QuickTime format, useful for intermediate files:
const renderer = new Renderer({
videoCodec: 'prores',
audioCodec: 'pcm_s16le'
});
await renderer.render(url, './output.mov');
Compatible codecs:
- ProRes (
prores, prores_ks)
- DNxHD (
dnxhd)
- PCM audio (
pcm_s16le, pcm_s24le)
Video codecs
H.264 (libx264)
Best compatibility and hardware support:
const renderer = new Renderer({
videoCodec: 'libx264',
preset: 'medium',
crf: 23, // 0-51, lower = better quality
pixelFormat: 'yuv420p'
});
Encoding speed vs compression ratio:
'ultrafast': Fastest encoding, largest file
'superfast', 'veryfast', 'faster', 'fast'
'medium': Balanced
'slow', 'slower', 'veryslow': Smaller file, slower encoding
Constant Rate Factor (quality):
0: Lossless (huge files)
18-23: High quality (recommended)
23-28: Good quality
28-35: Lower quality (smaller files)
51: Lowest quality
Optimize for specific content:
'film': Feature film content
'animation': Animated content
'grain': Preserve grain
'stillimage': Slideshow content
H.265 (libx265)
Better compression than H.264, but slower encoding:
const renderer = new Renderer({
videoCodec: 'libx265',
preset: 'medium',
crf: 28, // Use higher CRF than H.264 for similar quality
pixelFormat: 'yuv420p'
});
H.265 achieves similar quality to H.264 at ~50% smaller file size, but:
- Encoding is 5-10x slower
- Requires modern players (may not work on older devices)
- Patent licensing issues in some regions
VP9 (libvpx-vp9)
Royalty-free codec for web delivery:
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
crf: 30,
videoBitrate: '2M', // Target bitrate
audioCodec: 'libvorbis'
});
await renderer.render(url, './output.webm');
VP9 options:
- Similar quality to H.265
- Better than H.264 at low bitrates
- Native support in all modern browsers
- Slower encoding than H.264
AV1 (libaom-av1)
Next-generation codec with best compression:
const renderer = new Renderer({
videoCodec: 'libaom-av1',
crf: 30,
preset: 'fast', // AV1 encoding is VERY slow
pixelFormat: 'yuv420p'
});
AV1 encoding is extremely slow. A 10-second 1080p video can take 30+ minutes even on fast hardware. Use only when file size is critical.
Consider using libsvtav1 for faster AV1 encoding:
const renderer = new Renderer({
videoCodec: 'libsvtav1',
crf: 30,
preset: '8' // 0-13, higher = faster
});
Hardware-accelerated codecs
NVIDIA NVENC
Fast encoding on NVIDIA GPUs:
const renderer = new Renderer({
hwAccel: 'cuda',
videoCodec: 'h264_nvenc',
preset: 'p4', // p1-p7, higher = better quality
videoBitrate: '5M'
});
NVENC presets:
'p1': Fastest
'p4': Balanced
'p7': Best quality
Also available: hevc_nvenc for H.265
Intel Quick Sync (QSV)
Hardware encoding on Intel CPUs:
const renderer = new Renderer({
hwAccel: 'qsv',
videoCodec: 'h264_qsv',
preset: 'medium'
});
Also available: hevc_qsv, vp9_qsv
Hardware encoding on macOS:
const renderer = new Renderer({
hwAccel: 'videotoolbox',
videoCodec: 'h264_videotoolbox',
videoBitrate: '5M'
});
Also available: hevc_videotoolbox, prores_videotoolbox
AMD VCE/VCN
Hardware encoding on AMD GPUs:
const renderer = new Renderer({
hwAccel: 'vaapi', // On Linux
videoCodec: 'h264_vaapi'
});
Audio codecs
AAC
Most compatible audio codec:
const renderer = new Renderer({
audioCodec: 'aac',
audioBitrate: '192k' // 128k, 192k, 256k, 320k
});
Recommended bitrates:
'128k': Good quality
'192k': High quality (recommended)
'256k': Very high quality
'320k': Maximum quality (overkill for most uses)
Opus
Best quality per bitrate for WebM:
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
audioCodec: 'libopus',
audioBitrate: '128k'
});
Opus is more efficient than AAC at the same bitrate.
Vorbis
Open source codec for WebM:
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
audioCodec: 'libvorbis',
audioBitrate: '192k'
});
PCM (uncompressed)
Lossless audio for intermediate files:
const renderer = new Renderer({
audioCodec: 'pcm_s16le' // 16-bit PCM
});
Also available:
'pcm_s24le': 24-bit PCM (higher quality)
'pcm_s32le': 32-bit PCM
'pcm_f32le': 32-bit float PCM
yuv420p
Standard format, widest compatibility:
const renderer = new Renderer({
pixelFormat: 'yuv420p'
});
Limitations:
- No alpha channel
- 4:2:0 chroma subsampling
yuv444p
Full chroma resolution:
const renderer = new Renderer({
pixelFormat: 'yuv444p'
});
Benefits:
- No chroma subsampling
- Better color fidelity
- Larger file size
yuva420p
With alpha channel:
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
pixelFormat: 'yuva420p'
});
Alpha channel requires specific codecs (VP8, VP9, PNG). H.264 does not support alpha.
Common presets
High quality for archival
const renderer = new Renderer({
videoCodec: 'libx265',
preset: 'slow',
crf: 18,
pixelFormat: 'yuv420p',
audioCodec: 'aac',
audioBitrate: '256k'
});
Fast encoding for previews
const renderer = new Renderer({
videoCodec: 'libx264',
preset: 'ultrafast',
crf: 28,
audioCodec: 'aac',
audioBitrate: '128k'
});
Web optimized (small file size)
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
crf: 32,
videoBitrate: '1M',
audioCodec: 'libopus',
audioBitrate: '96k'
});
await renderer.render(url, './output.webm');
Hardware accelerated (NVIDIA)
const renderer = new Renderer({
hwAccel: 'cuda',
videoCodec: 'h264_nvenc',
preset: 'p4',
videoBitrate: '5M',
audioCodec: 'aac',
audioBitrate: '192k'
});
Transparent video
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
pixelFormat: 'yuva420p',
mode: 'canvas',
intermediateVideoCodec: 'vp8', // VP8 supports alpha
audioCodec: 'libvorbis'
});
await renderer.render(url, './output.webm');
Stream copy mode
Skip re-encoding for faster processing:
const renderer = new Renderer({
videoCodec: 'copy', // Copy video stream without re-encoding
mode: 'canvas',
intermediateVideoCodec: 'avc1.4d002a' // Must match final codec
});
When using videoCodec: 'copy', the intermediate codec must match the desired output codec. WebCodecs must be enabled (canvas mode).
Use stream copy when:
- Adding/removing audio tracks
- Trimming video
- Changing container format
Do not use when:
- Changing resolution
- Changing codec
- Burning in subtitles
Bitrate control
Constant Rate Factor (CRF)
Quality-based encoding:
const renderer = new Renderer({
videoCodec: 'libx264',
crf: 23 // Target quality, file size varies
});
Best for:
- Variable content complexity
- Archival
- When quality is more important than file size
Constant Bitrate (CBR)
Fixed bitrate:
const renderer = new Renderer({
videoCodec: 'libx264',
videoBitrate: '5M' // Exact bitrate, quality varies
});
Best for:
- Streaming
- Predictable file sizes
- Broadcast requirements
Two-pass encoding
For CBR, FFmpeg can use two-pass encoding (not currently exposed in Helios API):
# Pass 1
ffmpeg -i input.mp4 -c:v libx264 -b:v 5M -pass 1 -f null /dev/null
# Pass 2
ffmpeg -i input.mp4 -c:v libx264 -b:v 5M -pass 2 output.mp4
For web delivery
// Modern browsers
const renderer = new Renderer({
videoCodec: 'libvpx-vp9',
crf: 30,
audioCodec: 'libopus',
audioBitrate: '128k'
});
await renderer.render(url, './output.webm');
// Instagram, TikTok, YouTube
const renderer = new Renderer({
width: 1080,
height: 1920, // Vertical video
videoCodec: 'libx264',
preset: 'medium',
crf: 23,
pixelFormat: 'yuv420p',
audioCodec: 'aac',
audioBitrate: '192k'
});
For broadcast/professional
// ProRes for editing
const renderer = new Renderer({
videoCodec: 'prores_ks',
profile: 2, // ProRes 422
audioCodec: 'pcm_s24le'
});
await renderer.render(url, './output.mov');
For maximum compatibility
// Works everywhere, including old devices
const renderer = new Renderer({
videoCodec: 'libx264',
preset: 'medium',
crf: 23,
pixelFormat: 'yuv420p',
audioCodec: 'aac',
audioBitrate: '128k'
});
await renderer.render(url, './output.mp4');