Search Docs
Loading...
Skip to content

To WebM

Export video compositions as WebM files with VP8, VP9 or AV1 video and Opus or Vorbis audio, and keep the transparency of the page.

5 mins
estimated time
GitHub

WebM is an open video format. Its codecs are royalty-free, so you can encode and publish them without a patent license. The engine bundles the VP8, VP9, AV1, Opus and Vorbis encoders, so a WebM export works on every Android device. Where the device has a hardware encoder for VP8 or VP9, the engine uses it.

This guide covers how to export a page to WebM, choose the codecs, keep the transparency of the page, and write the result to a file.

Export to WebM#

Call engine.block.exportVideo(...) with a page block, the timeline range and MimeType.WEBM. The method returns a ByteBuffer with the WebM file.

suspend fun exportWebm(
engine: Engine,
page: DesignBlock,
pageDuration: Double,
): ByteBuffer {
val videoBytes = engine.block.exportVideo(
block = page,
timeOffset = 0.0,
duration = pageDuration,
mimeType = MimeType.WEBM,
progressCallback = { progress ->
Log.i(
"ExportToWebmGuide",
"Encoded ${progress.encodedFrames} of ${progress.totalFrames} frames",
)
},
)
check(videoBytes.hasRemaining()) { "WebM export is empty" }
return videoBytes
}

Without options, the export encodes VP9 video and Opus audio. Every other ExportVideoOptions value, such as targetWidth, frameRate and videoBitrate, works the same as for an MP4 export. So do progress, cancellation and partial export.

Choose the Codecs#

Set videoCodec and audioCodec in ExportVideoOptions to choose the codecs. A WebM file holds VP8, VP9 or AV1 video and OPUS or VORBIS audio.

suspend fun exportWebmWithCodecs(
engine: Engine,
page: DesignBlock,
pageDuration: Double,
): ByteBuffer {
val options = ExportVideoOptions(
videoCodec = VideoCodec.VP8,
audioCodec = AudioCodec.VORBIS,
videoBitrate = 4_000_000,
)
val videoBytes = engine.block.exportVideo(
block = page,
timeOffset = 0.0,
duration = pageDuration,
mimeType = MimeType.WEBM,
progressCallback = {},
options = options,
)
check(videoBytes.hasRemaining()) { "VP8 WebM export is empty" }
return videoBytes
}
  • VP8 is the oldest of the three video codecs, and almost every player decodes it.
  • AV1 makes the smallest file at the same quality, but it takes the longest to encode.
  • A codec that WebM cannot hold, such as H264 or AAC, fails the export. The engine does not change the codec for you.

Keep the Transparency#

Set exportAlpha = true to keep the transparent areas of the page. The WebM file then has a second video stream with the transparency. Only VP8 and VP9 keep it.

suspend fun exportWebmWithAlpha(
engine: Engine,
page: DesignBlock,
pageDuration: Double,
): ByteBuffer {
// Hide the page background, so only the blocks on the page are opaque.
engine.block.setFillEnabled(page, enabled = false)
val background = engine.block.getChildren(page).first()
engine.block.setVisible(background, visible = false)
try {
val videoBytes = engine.block.exportVideo(
block = page,
timeOffset = 0.0,
duration = pageDuration,
mimeType = MimeType.WEBM,
progressCallback = {},
options = ExportVideoOptions(
videoCodec = VideoCodec.VP9,
exportAlpha = true,
),
)
check(videoBytes.hasRemaining()) { "alpha WebM export is empty" }
return videoBytes
} finally {
engine.block.setVisible(background, visible = true)
engine.block.setFillEnabled(page, enabled = true)
}
}
  • Hide the page fill and every block that covers the whole page. Otherwise no area of the page is transparent.
  • exportAlpha with AV1 or with MimeType.MP4 fails the export.
  • Whether a player shows the transparency depends on the player.

Handle Export Results#

The returned ByteBuffer stays in memory. Write it to app storage, upload it, or pass it to another Android API.

suspend fun writeWebmToTempFile(videoBytes: ByteBuffer): File = withContext(Dispatchers.IO) {
val outputFile = File.createTempFile("export-to-webm-", ".webm")
val videoData = videoBytes.asReadOnlyBuffer()
outputFile.outputStream().channel.use { channel ->
while (videoData.hasRemaining()) {
channel.write(videoData)
}
}
check(outputFile.length() > 0L) { "WebM output file is empty" }
outputFile
}

Troubleshooting#

  • The export fails with ENCODE.VIDEO_CODEC_CONTAINER_MISMATCH or ENCODE.AUDIO_CODEC_CONTAINER_MISMATCH: The codec does not fit the file type. Use VP8, VP9 or AV1 with OPUS or VORBIS for WebM, or leave the codecs at AUTO.
  • The export fails with ENCODE.VIDEO_ALPHA_UNSUPPORTED: Use VP8 or VP9 with MimeType.WEBM when exportAlpha is true.
  • The transparent areas are black: Set exportAlpha, hide the page fill and the background blocks, and play the file in a player that reads the transparency stream.
  • The export is slow: AV1 encodes in software. Use VP9 or VP8, or lower targetWidth, targetHeight and frameRate.

API Reference#

API Description
engine.block.exportVideo(block=_, timeOffset=_, duration=_, mimeType=_, progressCallback=_, options=_) Exports a page timeline to a video ByteBuffer.
ExportVideoOptions(videoCodec=_, audioCodec=_, exportAlpha=_, videoBitrate=_) Selects the codecs, the transparency stream and the bitrate.
engine.block.setFillEnabled(block=_, enabled=_) Hides the page fill before a transparent export.
engine.block.setVisible(block=_, visible=_) Hides a background block before a transparent export.

WebM Export Options#

Option Default Description
mimeType Required MimeType.WEBM for a WebM file.
videoCodec VideoCodec.AUTO VP8, VP9 or AV1. AUTO picks VP9 for WebM.
audioCodec AudioCodec.AUTO OPUS or VORBIS. AUTO picks Opus for WebM.
exportAlpha false Keeps the transparency of the page. Only VP8 and VP9.

Next Steps#