StableDiffusionBridge supports text-to-video generation with DiT-based models such as Wan and LTX. supportsVideoGeneration() tells you at runtime whether the currently loaded model supports it, so you can conditionally expose the feature without hardcoding model names.

Check for video support

Always call supportsVideoGeneration() after initModel before offering video generation to users.

val ok = StableDiffusionBridge.initModel(
    modelPath = modelPath,
    vaePath = vaePath,
    t5xxlPath = t5xxlPath,
    clipVisionPath = clipVisionPath,
)
check(ok)

val videoSupported = StableDiffusionBridge.supportsVideoGeneration()

Initialize a video model

DiT-based video models (Wan, LTX) require companion files in addition to the main model file. Pass them as optional parameters to initModel.

val modelPath       = StableDiffusionBridge.getModelPath("wan-video.gguf")
val vaePath         = StableDiffusionBridge.getModelPath("wan-vae.safetensors")
val t5xxlPath       = StableDiffusionBridge.getModelPath("t5xxl_fp16.safetensors")
val clipVisionPath  = StableDiffusionBridge.getModelPath("clip_vision.safetensors")

val ok = StableDiffusionBridge.initModel(
    modelPath      = modelPath,
    threads        = 4,
    vaePath        = vaePath,
    t5xxlPath      = t5xxlPath,
    clipVisionPath = clipVisionPath,
)
check(ok) { "Failed to initialize video model" }

Generate video frames

val raw = StableDiffusionBridge.txt2video(
    prompt         = "A llama walking through a futuristic city",
    negativePrompt = "blurry, low quality",
    width          = 512,
    height         = 512,
    videoFrames    = 16,
    fps            = 8,
    cfgScale       = 7.0f,
    seed           = 42L,
)

Parse the result

txt2video returns a packed ByteArray. The first 16 bytes are a little-endian header followed by the raw RGBA frame data.

[frameCount : 4 bytes LE][width : 4 bytes LE][height : 4 bytes LE][fps : 4 bytes LE]
[frame 0 RGBA bytes: width * height * 4]
[frame 1 RGBA bytes: width * height * 4]
...

Kotlin unpacking example:

import java.nio.ByteBuffer
import java.nio.ByteOrder

fun parseVideoResult(raw: ByteArray): List<ByteArray> {
    if (raw.isEmpty()) return emptyList()

    val header = ByteBuffer.wrap(raw, 0, 16).order(ByteOrder.LITTLE_ENDIAN)
    val frameCount = header.int
    val width      = header.int
    val height     = header.int
    // fps is at header.int — read if needed

    val frameSize = width * height * 4
    val frames = mutableListOf<ByteArray>()
    for (i in 0 until frameCount) {
        val offset = 16 + i * frameSize
        frames.add(raw.copyOfRange(offset, offset + frameSize))
    }
    return frames
}

val frames = parseVideoResult(raw)

If raw is empty, generation failed.

VideoSaver (from the shared module) encodes and saves the frames as an H.264 video to the device gallery.

import com.llamatik.app.platform.VideoSaver

val saved = VideoSaver.saveVideo(
    frames = frames,
    width  = 512,
    height = 512,
    fps    = 8,
)
if (saved) println("Video saved to gallery")

saveVideo is a suspend function — call it from a coroutine.

Upscale a generated clip

VideoUpscalerBridge increases the resolution of a clip with a video super-resolution model. It works on the same packed result txt2video returns, and returns the same layout with the new size in its header.

VideoUpscalerBridge.initModel(upscalerModelPath, upscalerVaePath, upscaleFactor = 2)

val upscaled = VideoUpscalerBridge.upscale(packedBytes)   // call from a background thread

Parse upscaled exactly as shown above. See VideoUpscalerBridge for the options and platform support.

Parameter guidance

ParameterDefaultNotes
width / height512Start with 512×512; larger sizes increase memory and generation time significantly
videoFrames16Number of frames. Higher = longer clip, but proportionally slower
fps8Playback frame rate. Does not affect generation speed
cfgScale7.0Prompt adherence. 6.0–8.0 is a typical starting range
seed-1LUse a fixed value for reproducible clips, -1L for random

Platform notes

PlatformVideo generationGallery save
AndroidSupportedMediaCodec H.264 + MediaStore
iOSSupportedAVAssetWriter H.264 + PHPhotoLibrary
JVM / DesktopStub — returns falseNot available
WASMStub — returns falseNot available

iOS: add NSPhotoLibraryAddUsageDescription to your Info.plist before calling VideoSaver.saveVideo, otherwise the save call will fail silently.