-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration and profiles
src/config.cpp, src/config.h, src/json.cpp
CapView.json, beside the executable. Nothing is written to the registry —
the one exception being the virtual camera's COM registration, which has to be
machine-wide and is not CapView's own setting. See Virtual camera.
The JSON parser and writer are hand-written (src/json.cpp, 450 lines) rather
than pulled in as a dependency. The file is small, the schema is known, and every
read goes through a defaulting accessor:
app.settingsTab = a["settingsTab"].AsInt(0);A missing or malformed key yields the default instead of an error, so a config file from an older build always loads.
struct Profile {
std::string name = "Standard";
CaptureSettings capture; // device, input, format, video standard
ImageSettings image; // scaling, deinterlacing, composite filter, crop, colour
AudioSettings audio; // devices, buffer, offset, volume, microphone
};One per source. Selected with Ctrl+1 to Ctrl+9, which is deliberately not rebindable — see Shortcuts.
A profile is everything that depends on what is plugged in. Switching profiles restarts the capture graph, because the device or the format may have changed.
The usual way to make one, and the reason there is no plain "Duplicate" any more. Connecting a second console almost never means starting over: you change what is different and want to keep the result. An empty profile forces you to set up everything that was already right.
It copies the active profile — which is the current state, since settings take
effect immediately and are written there — and opens the name prompt with the
keyboard focus already in the field. SetKeyboardFocusHere() fires only on the
popup's first frame, or it would grab the input again every frame.
Hiding a control is not enough. Somebody who had the dot crawl filters and a native pixel grid set for a SNES, and then plugs in an HD console, would otherwise be looking at a picture they did not ask for with no control anywhere to change it — the control is gone precisely because it does not fit.
App::EffectiveImage() returns the settings as they apply to the current
source, and it is that copy which is drawn:
| Neutralised | When |
|---|---|
chromaSoft, temporalDenoise, dotNotch, nativeWidth, lineDouble
|
the source is not analogue |
scanlines, mask
|
the source is taller than 576 lines |
a hand-picked deinterlacer (forced to deinterlaceAuto) |
the source has no fields |
It neutralises the copy, never the profile. The stored values survive, because a profile describes a console and that console will come back.
What it deliberately does not do is remember and restore across a source change. The next analogue source may be a different console wanting different values, so restoring would be a guess. That is what profiles are for.
The same predicate, App::SourceIsAnalogue(), drives both what the settings
show and what the renderer applies. Two answers to one question would mean
something acting where nothing can be adjusted.
Measured, with nativeWidth set to 256 against a 1080p source: with the signal
type forced to Analogue the grid applies and a row shows 55 column
transitions; on Automatic, where 1080 lines cannot have come from an analogue
decoder, the same row shows 240. The setting is dropped, not merely hidden.
What is not in a profile — AppSettings — is everything that depends on
you: theme, accent colour, language, vsync, always-on-top, cursor hiding, sleep
prevention, the toolbar, the overlay level, where the settings window sits, which
tab it was on, and every recording, encoder and update setting.
Two places in the configuration carry an index into a table rather than a value, and both are noted in the source at the table:
-
videoStandard— the index intokStandardsinsrc/capture/dshow_util.cpp. Entries may be appended but never reordered. -
speed— the old software encoder speed, kept working alongside the newer preset setting so nobody's existing configuration changes meaning. See Encoder settings.
preventSleep, on by default. Playing a game through a capture card involves no
keyboard or mouse input as far as Windows is concerned, so the screen saver would
come on mid-session. App calls SetThreadExecutionState periodically while a
capture is running.
Not configuration, but it lives in the same folder and is worth knowing about.
Compiled shaders are cached as shader-<hash>.cso next to the executable, keyed
by an FNV-1a hash of the source text and the compile target. That is what keeps
startup fast — the composite filter alone takes seconds to compile.
PruneShaderCache() runs at startup and deletes every shader-*.cso that is not
in the list this build actually uses:
for (const std::wstring& used : ShaderCacheInUse()) { … }
if (!live && ::DeleteFileW(path.c_str())) ++removed;A failed delete is not an error — if a second instance is holding the file, the next start gets another turn.
Without this, every shader edit in every build left its cache file behind forever.