dasVideo
June 21, 2026 · View on GitHub
Living checklist. Frozen design rationale in ORIGINAL_PLAN.md. No time/effort sizing — it takes what it takes.
Legend: [ ] todo · [~] in progress · [x] done
P0 — Scaffold + CI (foundation; green from commit one)
- CMake linking daslang via
DASLANG_DIR(dasVulkan-style);.shared_moduleoutput -
.das_module(loadsdasModuleVideo.shared_module; needsrequire daslib/fio) -
vendor/pl_mpeg.h(MIT, compiled into the module TU) -
LICENSE(MIT),README.md,.gitignore,.gitattributes -
CLAUDE.md(repo instructions for AI collaboration) -
doc/Sphinx skeleton - empty module compiles + headless smoke passes (proven locally on Windows)
- [~] CI: Linux + macOS build + headless smoke (regular GitHub runners). Windows CI
is a fast-follow — the module build is proven locally; the daslang Windows
build still needs bison/flex + MSVC env wiring on
windows-latest.
P1 — pl_mpeg video (headless)
-
video_open→VideoPlayerhandle (opaque); info via getters (width/height/framerate/samplerate/duration/frame_time, y/uv strides). A plain frame-info struct is ergonomic sugar deferred to the daslib boost layer. -
video_decode→ native YUV420p planes (borrow-until-next-decode) -
get_datablock accessor — YUV planes (zero-copyarray<uint8>#views) - C++ YUV→RGB converter (
plm_frame_to_rgba);get_data— RGBA8 - [~] headless decode-N-frames + checksum test (green: local Windows + CI Linux/macOS; Windows CI shares P0's fast-follow)
P2 — GL output
-
examples/play_rgba_gl— RGBA → one texture, fullscreen quad; clargs CLI, loop-by-default (--noloop/--max-frames/--scale/--shot). Visually verified (test pattern renders in a window). Surfaced + fixed an opaque-alpha bug in the RGBA converter along the way. -
examples/play_yuv_gl— 3×GL_R8textures + YUV→RGB fragment shader (BT.601, matches pl_mpeg). Per-planeGL_UNPACK_ROW_LENGTHfor the macroblock-rounded strides;@stage = 0/1/2to bind the 3 samplers to distinct units. Visually verified against the RGBA path.
Follow-ups
- daslang teardown crash (was: clargs early-exit like
--help+ the GL stack →g_envTotal=1). Root cause:defer-loweredfinallyran on the earlyreturnand read a finally-referenced local whose stack slot the interpreter's reuse optimization had handed to an earlier sub-scope, clobbering its zero → garbage pointer → AV. Fixed upstream in daslang (disable slot reuse for blocks with afinalList) + regression test. No dasVideo change was needed.
P3 — Audio + sync
- decode MP2 → interleaved float PCM (
video_decode_audio+get_audio_databorrow; audio is opt-in viavideo_enable_audioso video-only paths stay zero-overhead) -
play_sound_from_pcm_stream+append_to_pcmtop-up loop (feed_audio,AUDIO_TARGET_CHUNKSslack) -
consumed_positionmaster clock;stream_que_lengthbackpressure - pace loop: top-up / promote-when-due / drop-intermediate; clean looping via drain-then-restart (re-anchor the clock so A/V stays in sync across the boundary)
- silent / no-audio wall-clock fallback (
--mute+ auto when no audio stream) -
examples/play_audio_gl— windowed A/V-synced player (real playback verified:consumed_positionadvances, video frames pace to it) - test with an audio-bearing clip (
tests/test_audio.das+test_audio.mpgfixture; device-free decode+borrow, wired into CI)
Demo presenter — Emma
- Emma — synthetic face + voice (Kokoro
bf_emma→ Sonic talking-head). The full reproducible recipe is inEMMA.md; canonical source faces inassets/emma/.assets/emma/emma_intro.mpg(1024 master → 384×384 MPEG-1/MP2) isplay_audio_gl's default, so the audio demo is "Emma introduces dasVideo" with real A/V sync.
Plan order (per Boris): docs/tutorials → daspkg → AV1 after. (P4 imgui later.)
P6 — Docs + tutorials ← NEXT
- Sphinx reference content (per-API) for the current surface (open/decode/get_data/ get_audio_data/the audio-sync model)
- tutorial ladder: open-probe → rgba-to-gl → yuv-shader → audio-sync → (imgui-embed) → (av1)
- recordings (voiced, self-verifying) per the standard pipeline — Emma fronts them
daspkg — register (unblocked: it's demoable now)
- daspkg-index entry;
build()→cmake_build()setsDASLANG_DIR
P4 — dasImgui (later)
-
image()embed in an imgui window — flagship demo
P5 — dav1d backend (the AV1 follow-up, after docs/daspkg)
- vendor dav1d; WebM demux; Opus/Vorbis audio decode
- behind the same
VideoSourceAPI; backend selection by probe/extension
Cross-cutting
- CI stays green every phase;
//!docstrings written with the code - daspkg-index entry (publish once demoable)
Deferred
- WASM target — BLOCKED: daslang WASM backend lacks OpenGL + dasAudio. Revisit after that gap is closed upstream.