KVID is a Kotlin Multiplatform library that stores text as QR codes inside MP4 video frames and keeps the data searchable through semantic embeddings and vector indexes.
KVID is a Kotlin Multiplatform port and evolution of MemVid, originally written in Python. While MemVid focused on server-side LLM memory systems, KVID extends the concept to mobile and cross-platform environments with native support for Android, iOS, and JVM. Both projects share the core innovation of using video compression for efficient text storage with QR codes, but KVID adds multiplatform capabilities, hardware-accelerated encoding, and enhanced semantic search features.
- QR code generation and decoding across JVM/Android/iOS
- Video encoding/decoding adapters (FFmpeg/MediaCodec/VideoToolbox)
- Text chunking, embeddings, and in-memory vector indexes
- High-level APIs:
MemoryStore,MemoryEncoder, andMemoryDecoder
- FFmpeg (optional, for JVM video encoding)
kvid-core/– shared APIs and platform wiring undersrc/commonMain,androidMain,jvmMain, andiosMainkvid-examples/– runnable samples and benchmarks invoked via./gradlew :kvid-examples:run
./gradlew build # Build everything and run tests
./gradlew :kvid-core:test # Core tests onlyimport com.kvid.core.*
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
val store = MemoryStore(chunkSize = 256)
store.addMessages(
listOf(
Message(id = 1, content = "Hello, world"),
Message(id = 2, content = "Semantic search is handy")
)
).getOrThrow()
val results = store.search("greeting", topK = 3).getOrThrow()
results.forEach { println("${(it.relevance * 100).toInt()}% → ${it.content}") }
}Run examples from the repo root:
./gradlew :kvid-examples:run --args="<example>"- Default (no args): Basic memory-store demo with semantic search and stats
persistence: Create → search → save (.bin) → load → update flow; files land inkvid-examples/kvid-data/persistence-load: Load an existing index (runpersistencefirst) and perform searchesadvanced: Batch insert and search timing over synthetic datachunking: Inspect howTextChunkersplits and annotates textvector-index: Work directly withInMemoryVectorIndexembedding: Compare semantic similarity scores between textsbenchmark: Standard benchmarks (~3 minutes) - text chunking, QR generation, embeddings, vector search, video encoding/decodingbenchmark-advanced: Advanced benchmarks (~15 minutes) - memory profiling, scalability testing, parameter tuningbenchmark-stress: Stress benchmarks (~20 minutes) - large dataset handling, long-running operations, memory leak detectionqrtest: Basic QR-code sanity check
KVID allows you to save and load vector indexes for persistent storage:
# Step 1: Create and save data
./gradlew :kvid-examples:run --args="persistence"
# Step 2: Load and search saved data
./gradlew :kvid-examples:run --args="persistence-load"// Create and save
val store = MemoryStore(chunkSize = 256)
store.addMessages(messages).getOrThrow()
val embedding = SimpleEmbedding()
val index = JvmHnswVectorIndex(embedding)
// Add vectors...
index.save("/path/to/index.bin").getOrThrow()
// Load and search
val index = JvmHnswVectorIndex(embedding)
index.load("/path/to/index.bin").getOrThrow()
val results = index.search(queryVector, topK = 5)File Locations: Saved indexes are stored in kvid-examples/kvid-data/ with .bin extension (e.g., messages-index.bin).
Encoding Pipeline:
Text Messages → TextChunker → QR Codes → Video Frames → MP4 File
↓
Embeddings → Vector Index
Search Pipeline:
User Query → Embedding → Vector Search → Frame IDs → QR Decode → Messages
KVID uses Kotlin Multiplatform with platform-specific implementations:
- commonMain/: Interfaces and core logic (TextChunker, SemanticEmbedding, etc.)
- androidMain/: MediaCodec for hardware-accelerated video encoding
- jvmMain/: FFmpeg wrapper for video encoding
- iosMain/: VideoToolbox and AVFoundation for video encoding
- QRCodeGenerator: Converts text to QR code images (ZXing on JVM/Android, Core Image on iOS)
- VideoEncoder/Decoder: Handles MP4 video creation and frame extraction
- SemanticEmbedding: Generates vector representations of text
- VectorIndex: Stores and searches embedding vectors (InMemoryVectorIndex, HNSW)
- TextChunker: Splits text into semantic chunks with configurable size and overlap
val store = MemoryStore(chunkSize = 512)// Add messages
store.addMessages(listOf(
Message(id = 1, content = "Your message here", source = "user_1")
)).getOrThrow()
// Search
val results = store.search("query", topK = 5).getOrThrow()
results.forEach { println("${it.relevance}: ${it.content}") }val chunker = TextChunker(
chunkSize = 512,
overlapSize = 32,
preserveSentences = true
)
val chunks = chunker.chunk("Your long text...")val embedding = SimpleEmbedding()
val vector = embedding.embed("Hello world")
val similarity = embedding.similarity(vec1, vec2)val encoder = MemoryEncoder(
qrGenerator = JvmQRCodeGenerator(),
videoEncoder = JvmVideoEncoder(),
chunkSize = 512
)
encoder.addMessage("Message 1").getOrThrow()
encoder.buildVideo("output.mp4", params).getOrThrow()KVID includes comprehensive benchmarking:
- Text Chunking: 20,000+ chunks/sec
- QR Generation: 100+ QR codes/sec
- Embedding (Single): 100+ embeddings/sec
- Vector Search (HNSW): 20-67 queries/sec
- Video Compression: 50:1 to 150:1 ratio
- Memory per Vector: 1,800-2,500 bytes
./gradlew :kvid-examples:run --args="benchmark" # Quick test (~3 min)
./gradlew :kvid-examples:run --args="benchmark-advanced" # Deep analysis (~15 min)
./gradlew :kvid-examples:run --args="benchmark-stress" # Stress test (~20 min)KVID uses MediaCodec for hardware-accelerated video encoding on Android (API 21+):
Features:
- Hardware-accelerated encoding when available
- Automatic fallback to software encoding
- Support for H.264, H.265, VP9, and AV1 codecs
- RGB to YUV420 color space conversion
- Frame-by-frame encoding with proper timestamps
Usage:
val encoder = AndroidVideoEncoder()
encoder.initialize(VideoEncodingParams(256, 256, 30, VideoCodec.H264))
encoder.addFrame(frameData, frameNumber).getOrThrow()
val stats = encoder.finalize("/path/to/output.mp4").getOrThrow()Codec Detection:
val codecs = getAvailableVideoCodecs() // ["H.264", "H.265", "VP9"]KVID uses native Apple frameworks for iOS (iOS 11.0+):
Components:
- QR Generation: Core Image's CIFilter
- Video Encoding: AVFoundation + VideoToolbox (H.264/H.265)
- Video Decoding: AVFoundation's frame extraction
- QR Decoding: Vision Framework's barcode detection
Features:
- Hardware-accelerated video encoding/decoding
- No external dependencies (native frameworks only)
- Full async/coroutine support
Usage:
val generator = IosQRCodeGenerator()
val encoder = IosVideoEncoder()
val decoder = IosVideoDecoder()
val qrDecoder = IosQRCodeDecoder()Core APIs, QR generation, chunking, embeddings, and in-memory search are implemented. Video encoding/decoding is production-ready on Android and iOS, with JVM support via FFmpeg. See the examples section above for the latest runnable flows.
MIT License