Export the video editor’s result as a WebM file with VP9 video and Opus audio, on iOS and on Android.
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 WebM encoders, so the export works the same on every iOS and Android device.
The @imgly/editor-react-native module uses the native iOS and Android editors, and the default video editor exports
MP4. To export WebM, replace the video editor natively on both platforms through the module’s builderClosure. Your
JavaScript code stays the same: IMGLYEditor.openEditor() returns an EditorResult whose artifact points to the
WebM file.
iOS#
Assign a custom builder for the video preset. Call useWebmVideoEditor() before you open the editor, for example in
AppDelegate.application(_:didFinishLaunchingWithOptions:).
import IMGLYEditorimport IMGLYEditorModuleimport IMGLYEngineimport SwiftUIIMGLYEditorModuleSwiftAdapter.shared.builderClosure = { preset, _ in if preset == .video { webmVideoEditor() } else { EditorBuilder.design() }}The custom editor is the default video editor with one change: the onExport callback passes .webm to
OnExport.exportVideo. The helper shows the export progress, writes the file with the .webm extension and returns
the EditorResult to React Native.
private func webmVideoEditor() -> EditorBuilder.Builder { EditorBuilder.custom { settings, _, _, result in WebmVideoEditor(settings: settings, result: result) }}
// The `custom` closure is not isolated to the main actor, so the editor is built in `body`, which is.private struct WebmVideoEditor: View { let settings: EditorSettings let result: EditorBuilder.EditorBuilderResult
var body: some View { NavigationView { Editor(EngineSettings( license: settings.license, userID: settings.userId, baseURL: URL(string: settings.baseUri), host: "react-native", )) .imgly.configuration { VideoEditorConfiguration { builder in builder.onCreate { engine, _ in if let createScene = try OnCreate.loadFromSettings(settings) { try await VideoEditorConfiguration.defaultOnCreate(createScene: createScene)(engine) } else { try await VideoEditorConfiguration.defaultOnCreate()(engine) } } builder.onExport { engine, eventHandler, _ in do { let editorResult = try await OnExport.exportVideo(engine, eventHandler, .webm) result(.success(editorResult)) } catch { if error is CancellationError { return } result(.failure(error)) } } } ModalEditorConfiguration(result: result) } } .navigationViewStyle(.stack) }}Android#
Assign a custom builder for the video preset, for example in MainApplication.onCreate. The custom editor needs the
Compose setup from the customization guide.
import androidx.compose.runtime.Composableimport androidx.core.net.toUriimport kotlinx.coroutines.CancellationExceptionimport ly.img.editor.Editorimport ly.img.editor.configuration.video.VideoConfigurationBuilderimport ly.img.editor.configuration.video.callback.onCreateimport ly.img.editor.configuration.video.callback.onExportimport ly.img.editor.configuration.video.model.ExportStatusimport ly.img.editor.core.configuration.EditorConfigurationimport ly.img.editor.core.configuration.rememberimport ly.img.editor.reactnative.module.IMGLYEditorModuleimport ly.img.editor.reactnative.module.builder.EditorBuilderimport ly.img.editor.reactnative.module.builder.EditorBuilderDefaultsimport ly.img.editor.reactnative.module.builder.EditorBuilderResultimport ly.img.editor.reactnative.module.model.EditorPresetimport ly.img.editor.reactnative.module.model.EditorSettingsimport ly.img.engine.MimeTypeIMGLYEditorModule.builderClosure = { preset, _ -> if (preset == EditorPreset.VIDEO) { EditorBuilder.custom { WebmVideoEditor(settings, result, onClose) } } else { EditorBuilder.design() }}The custom editor replaces the exportByteBuffer step of onExport. It calls engine.block.exportVideo with
MimeType.WEBM and updates exportStatus, so the editor shows the progress.
EditorBuilderDefaults.getExportResult writes the file with the .webm extension and returns the EditorResult to
React Native.
@Composableprivate fun WebmVideoEditor( settings: EditorSettings, result: EditorBuilderResult, onClose: (Throwable?) -> Unit,) { Editor( license = settings.license, host = "react-native", baseUri = settings.baseUri.toUri(), userId = settings.userId, configuration = { EditorConfiguration.remember(::VideoConfigurationBuilder) { onCreate = { onCreate( createScene = { EditorBuilderDefaults.onCreateScene( scope = this@Editor, settings = settings, defaultUri = "file:///android_asset/scene/video.scene".toUri(), ) }, ) } onExport = { onExport( exportByteBuffer = { val engine = editorContext.engine val page = requireNotNull(engine.scene.getCurrentPage()) engine.block.exportVideo( block = page, timeOffset = 0.0, duration = engine.block.getDuration(page), mimeType = MimeType.WEBM, progressCallback = { progress -> exportStatus = ExportStatus.Loading( progress = progress.encodedFrames.toFloat() / progress.totalFrames, ) }, ) }, postExport = { val editorResult = EditorBuilderDefaults.getExportResult( scope = this@Editor, byteBuffer = it, mimeType = MimeType.WEBM, ) exportStatus = null result(Result.success(editorResult)) }, error = { exportStatus = null if (it !is CancellationException) { result(Result.failure(it)) } }, ) } } }, ) { onClose(it) }}Choose the Codecs#
Without options, a WebM export encodes VP9 video and Opus audio. To select VP8 or AV1, Vorbis audio, or a
transparency stream, pass export options to exportVideo in the native code. The
iOS guide and the Android guide
show these options.
Troubleshooting#
- The editor still exports MP4: The module uses its default video editor when
builderClosureis not set. Assign the closure before you callIMGLYEditor.openEditor(), on both platforms. - The export fails with
ENCODE.VIDEO_CODEC_CONTAINER_MISMATCHorENCODE.AUDIO_CODEC_CONTAINER_MISMATCH: A codec in the export options does not fit WebM. Use VP8, VP9 or AV1 with Opus or Vorbis. - The file does not play on iOS: AVFoundation does not play WebM. Upload the file, or play it with a player that supports WebM.
Next Steps#
- Customization - Replace or configure the native editors
- Export Overview - Compare all supported export formats