English | 简体中文
Light up local videos as system virtual cameras. Pick them in any meeting or streaming app — you decide what plays.
Two components:
| Component | Path | Description |
|---|---|---|
| dfvcam backend | src/ |
C++ virtual camera engine: multi-instance virtual cameras on Windows 11's MFCreateVirtualCamera (Media Foundation, not DirectShow) + video decoding/streaming + WASAPI audio + HTTP control API |
| Neon desktop console | ui/ |
Tauri 2 + React 19 GUI: create cameras, drag-and-drop playlists, preview popups, playback/audio control, all driving the backend over its HTTP API → ui/README.md |
Repository layout
├─ src/ Backend sources (server exe + vcamsource DLL + common protocol)
├─ ui/ Neon desktop console (Tauri 2 + React)
├─ docs/ HTTP API reference, acceptance records
├─ scripts/ Elevated install / packaging scripts
├─ tests/ Backend unit tests (gtest)
└─ examples/ API usage example scripts
# 1. Build the backend (needs VS2022 + vcpkg; dependencies pulled automatically)
cmake --preset vs2022
cmake --build --preset release
# 2. One-time install (admin: registers the media source DLL)
.\build-static\src\server\Release\dfvcam.exe install
.\build-static\src\server\Release\dfvcam.exe doctor # self-check, expect all ok
# 3. Start the service
.\build-static\src\server\Release\dfvcam.exe serve
# 4. Desktop console (optional — plain HTTP works too)
cd ui && npm install && npm run tauri dev
# 5. Pick "<camera name> Windows Virtual Camera" in your meeting/streaming appPrefer not to build? Grab the installer from Releases.
dfvcam.exe (control service, user session)
├─ drogon HTTP API (127.0.0.1:8686)
├─ per camera:
│ ├─ PlaybackEngine Source Reader decode → scale/convert to fixed WxH NV12 → timestamp pacing
│ ├─ AudioOutput WASAPI shared rendering to the chosen device (AUTOCONVERTPCM)
│ ├─ PipeServer \\.\pipe\dfvcam.slotNN frame broadcast + config handshake
│ └─ IMFVirtualCamera registration (Session lifetime, CurrentUser)
└─ config.json persistence
dfvcam_source.dll (COM media source, loaded by the Frame Server service)
└─ 16 slot CLSIDs → MediaSource/MediaStream → pipe client receiving frames
renders a gray placeholder while the service is away
Frame path: the decoding process (dfvcam.exe) pushes NV12 frames over a named pipe to the media source inside the Frame Server; consumers (Teams/OBS/browsers) pull through the Frame Server. All control goes over HTTP.
Requirements: VS2022 + Windows SDK 22000+ (Win11), CMake, vcpkg (drogon / spdlog / simdjson / wil / gtest, installed automatically via manifest).
cmake --preset vs2022 # x64-windows-static: single-file binaries, no VC++ Redist
cmake --build --preset release
ctest --preset releaseArtifacts: build-static\src\server\Release\dfvcam.exe (~8MB fully static) + dfvcam_source.dll (copied next to it). Version info (including git hash) is embedded into file properties and dfvcam version.
# One-time, admin: copies the DLL to %ProgramData%\dfvcam\bin and registers 16 slot CLSIDs in HKLM
dfvcam install
# Self-check (no admin needed)
dfvcam doctor
# Start the service (regular user)
dfvcam serve --port 8686Cameras have Session lifetime: they exist while dfvcam serve runs and vanish when it exits. uninstall deregisters everything.
Virtual cameras
- Up to 16 running at once; name/resolution/framerate per camera (default 1280x720@30, up to 4096 / 120fps)
- Appear in the system camera list on creation, selectable by any meeting/streaming app; deleted = deregistered
- Name/resolution/framerate updatable in place (id preserved); concurrent multi-camera pulling is stable (dual 1080p30 measured at full framerate)
Playback
- Playlists play in order; prev/next (wrap-around), pause (audio+video resume at the same point), precise seek, stop
- Three loop modes: none / single / whole list
- Playlist swaps don't interrupt: if the current video survives into the new list it keeps playing, then follows the new order; or explicitly pick a start index
- Broken files are skipped automatically; an all-broken list lands in an error state with the reason
Audio
- Each camera picks its own WASAPI output device; volume/mute apply instantly
- Works as a virtual microphone together with VB-Cable (see audio boundary below)
Service
- Everything is controlled over the HTTP API (full reference: docs/http-api.md); the Neon console works out of the box
- Autoplay: starts playing when an app pulls the stream and the engine is idle
- While the service is offline the camera shows a placeholder and reconnects automatically
- Config auto-persists;
doctorone-shot self-check,pullreal-pipeline diagnostics, embedded traceable version
No auth by default. To require login for the HTTP API (and the Neon console):
- Stop the service ("shut down service" in Neon, or Ctrl+C) — editing the config while running gets overwritten by auto-persistence
- Edit
%LOCALAPPDATA%\dfvcam\config.jsonwith fixed credentials (no database):"auth": { "username": "admin", "password": "your-password" }
- Restart the service. Every endpoint then requires a JWT (obtained via
POST /auth/login, valid 24h); the Neon console shows a login screen automatically. Clearing either field disables auth again.
Details (token lifecycle, 401 semantics) in the auth section of
docs/http-api.md. The signing key is random per start,
so a service restart requires logging in again — keep auth off for
local-only use; enable it when binding to a LAN address (--host).
Media Foundation virtual cameras are video only. Windows has no user-mode "virtual microphone" API (that requires a signed kernel driver). This project's approach: the video's audio track is rendered to an output device of your choice. To make other apps treat it as a microphone, install VB-Audio Virtual Cable: dfvcam outputs to "CABLE Input", the meeting app picks "CABLE Output" as its mic.
- Resolution/framerate are fixed at camera creation (default 1280x720@30); every video is scaled/converted to that format (stretched, no letterboxing). Consumer-side framerate follows the Frame Server's pull cadence; repeated last frames are normal live semantics.
autoplay: true(default): playback starts when a consumer opens the camera while the engine is idle.- When the service is not running/disconnected, the camera shows a dark gray placeholder and reconnects automatically.
- An unplayable playlist item is logged and skipped; if the whole list fails the engine enters the error state.
- A/V sync: one Source Reader decodes both streams interleaved by timestamp; video paces against a steady clock, audio backpressures through WASAPI. No device-clock drift correction for very long videos (hours-scale sessions may drift).
- One slot per camera (16 total); config persists at
%LOCALAPPDATA%\dfvcam\config.json. - Logs: server at
%ProgramData%\dfvcam\logs\server_YYYY-MM-DD.log(after install; daily rotation, 7 days kept, debug-level detail including HTTP access and engine commands) + console; media source atsource_<pid>.log+ OutputDebugString. - HTTP listens on 127.0.0.1 by default with no auth; configure
auth: {username, password}in config.json to enable JWT authentication (POST /auth/loginissues a 24h token, invalidated on restart). Recommended when exposing to the LAN.
- Windows 11 22000+ only (
MFCreateVirtualCamera). - Renaming = recreating the virtual camera (the friendly name is part of the device identity); apps that had it open must reselect.
- The system appends "Windows Virtual Camera" to the name (OS behavior, prevents impersonating physical cameras).
- No images/audio-only files as playlist items (a video stream is required).
MIT.
The media source's interface surface and event contract were informed by smourier/VCamSample (MIT). Dependencies: drogon (MIT), spdlog (MIT), simdjson (Apache-2.0), WIL (MIT), Tauri (MIT/Apache-2.0).