A wgpu-native example that renders decoded NV12 video frames through Vello GPU's external-texture API (ImageSource::external_texture + TextureBindings::insert_wgpu_external_texture) backed by wgpu::ExternalTexture.
macOS only. Scans ~/Downloads/videos/ for .mp4 / .mov files, opens each through a small AVFoundation / VideoToolbox pipeline (see src/video/), decodes to NV12, and wraps the resulting Y/UV plane wgpu::Textures in a wgpu::ExternalTexture that Vello samples directly. wgpu performs the YCbCr → RGB conversion when Vello‘s shader loads from the external texture; there is no CPU-side or GPU-side intermediate RGBA copy. The plane textures are zero-copy — backed by the same IOSurfaces VT decoded into. All videos play simultaneously in a grid layout. A still image (assets/splash-flower.jpg, uploaded once with Renderer::upload_image) sits in the free space between the first two videos of the top row. A large yellow “Vello GPU” text overlay is rendered on top of the grid using Scene::glyph_run with the bundled Roboto font, and inherits the user’s pan / zoom / rotation.
On other platforms the binary still builds, but main immediately exits with a diagnostic — there is no software-decode fallback.
The macOS pipeline is a minimal AVFoundation / VideoToolbox decoder:
Demuxer (AVAssetReader, compressed CMSampleBuffers)
-> VideoDecoder (VTDecompressionSession, NV12 CVPixelBuffers in decode order)
-> MetalImporter (CVMetalTextureCache, one wgpu::Texture per plane)
-> VideoFrame { external_texture, pts_ns, color_space, ... }
-> VideoFileSource (reorders to display order, paces by timestamp)
-> Scene::set_paint (ImageSource::external_texture) + TextureBindings::insert_wgpu_external_texture
Each frame‘s wgpu::ExternalTexture is created from two plane views — a full-resolution R8Unorm Y plane and a half-resolution Rg8Unorm interleaved Cb/Cr plane — with ExternalTextureFormat::Nv12 and a YCbCr → RGB matrix built from the source’s color-space metadata (matrix coefficients and range). Vello's render.wesl sees a WGSL texture_external and receives RGB from textureLoad.
wgpu::Features::EXTERNAL_TEXTURE is required, which wgpu currently implements only on Metal, DX12 and WebGPU.
A frame's planes live in an IOSurface that VideoToolbox recycles once the frame is dropped. VideoFileSource therefore keeps each frame it takes off screen until the GPU reports (through Queue::on_submitted_work_done) that every submission that may have sampled it has finished.
Limitations:
preferredTransform), pixel aspect ratio and clean aperture are ignored, so portrait phone videos show sideways.The example reads every .mp4 / .mov in ~/Downloads/videos/ and needs at least one. Any H.264 / HEVC file that AVFoundation can open will do; the Blender Foundation's open movies are a good default since they are freely redistributable (Creative Commons Attribution) and are the de facto standard video test content:
mkdir -p ~/Downloads/videos cd ~/Downloads/videos # Big Buck Bunny (2008, CC BY 3.0) — 1280x720 H.264, ~400 MB curl -LO https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_h264.mov.zip unzip -j big_buck_bunny_720p_h264.mov.zip '*.mov' && rm big_buck_bunny_720p_h264.mov.zip # Tears of Steel (2012, CC BY 3.0) — 1280x534 H.264, ~370 MB curl -LO https://download.blender.org/demo/movies/ToS/tears_of_steel_720p.mov # Elephants Dream (2006, CC BY 2.5) — 720x405 H.264, ~150 MB curl -LO https://download.blender.org/ED/elephantsdream-720-h264-st-aac.mov # Sintel trailer (2010, CC BY 3.0) — 1920x1080 H.264, ~15 MB curl -LO https://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4
For a high-frame-rate stress test of the PTS pacing, the 2013 re-render at https://download.blender.org/demo/movies/BBB/ has 1080p / 2160p MP4s at 30 and 60 fps under the same license.
Only .mp4 and .mov extensions are picked up — rename .m4v files or add the extension to build_video_slots in src/main.rs. MKV / WebM are not supported by AVAssetReader and will be skipped with a warning.
If you reuse these clips, credit (c) Blender Foundation with the respective project URL (www.bigbuckbunny.org, mango.blender.org, orange.blender.org, www.sintel.org).
cargo run -p vello_gpu_wgpu_video --release
Esc — exitR — rewind / restart all videos from the first frame (also resets pan/zoom/rotation)L — toggle auto-replay (loop videos when they reach end-of-stream; on by default)Space — reset pan / zoom / rotation to identity[ / ] — rotate scene 15° counter-clockwise / clockwise around cursor (or window center if no cursor)