Skip to content

Latest commit

 

History

67 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CapView

A low-latency viewer and recorder for DirectShow capture cards on Windows.

The viewer in fullscreen showing a console at 1080p60, with the statistics overlay reading a frame age of 1.2 ms

CapView displays the output of a capture card with as little delay as the hardware allows, so the captured signal can be played on rather than only watched. Measured on a StarTech PEXHDCAP60L: 1080p60 sustained, around 1 ms between a frame arriving from the card and being drawn.

It is meant for using a capture card to play. Recording, screenshots, a microphone track and a virtual camera are included; scenes, overlays, compositing and streaming are not. For those, use OBS. It covers the same ground as AmaRecTV, whose last release with a bundled recording codec was version 3.10 in 2014.

The wiki is the detailed documentation — one page per feature, covering what the code does, why it works that way, and what was measured to arrive at it.

Latency

Four decisions account for the measured figure.

  • No queue in the capture path. The capture filter copies each frame into a triple buffer and returns immediately. Frames arriving faster than they can be shown are dropped rather than buffered, so delay cannot accumulate.
  • No graph clock. The DirectShow graph runs without a reference clock, so frames are not held back until a presentation time.
  • Flip-model swap chain, maximum frame latency of one, tearing permitted. VSync is off by default.
  • Format conversion on the GPU. YUY2, UYVY, YVYU, NV12, planar 4:2:0, RGB and P010 are unpacked in a pixel shader rather than on the CPU.

Details: Latency.

Features

Settings follow the source

The settings live in a window of their own by default, with its own Direct3D device, so it can be sized freely or moved to a second monitor. An embedded panel remains under Display, because a window capture in OBS cannot see a second window.

Their contents follow the source. Before a device is chosen there is nothing but the device picker; afterwards, controls that cannot apply are absent rather than disabled, and are not applied to the picture either:

Shown when
Native pixel grid, composite filter the source is analogue
Scanlines and CRT mask the source is 576 lines or fewer, analogue or not
Deinterlacing the source has fields at all
HDR source curve and source peak the source is not analogue

The test is the picture, not the socket: no analogue standard produces more than 576 lines, so a hybrid card delivering more is treated as digital however its decoder is reported.

The first run opens on a welcome screen rather than on the settings.

Source

Any DirectShow video device. Resolution, frame rate, pixel format and colour space are selected independently, so combinations a driver does not advertise but does accept can be forced — which covers the common case of a card reporting only 1080p30 for a mode it will in fact deliver at 1080p60.

Cards with an analogue decoder also expose their video standard — PAL, PAL-60, NTSC, SECAM and the rest. It matters on a console that does both 50 and 60 Hz: PAL is 625 lines at 50, PAL-60 is 525 at 60, and the wrong one gives either no picture or one with the wrong number of lines. An automatic mode cycles the plausible standards and keeps the first that locks. The standard belongs to the analogue decoder, so it is dropped whenever the input it described goes away, and a source declared Digital never gets one.

Configure card opens the driver's own property pages while the picture keeps running. Reinitialise card releases the card, finds it again and returns the standard and format to automatic, leaving the device and input alone — enough, after moving a card from composite to DVI, to have 1920×1080 at 60 found on its own.

Whether anything is coming in is measured from the pixels, not from whether frames arrive: an analogue card with nothing connected keeps delivering frames, and no signal on composite is snow rather than black.

More: Source and signal, Signal detection.

The Source tab: the capture device, the analogue video standard set to PAL 60, and the decoder reporting no lock because nothing was connected when this was taken

Picture

Nearest, bilinear, Catmull-Rom, Lanczos3 and sharp-bilinear scaling; contrast adaptive sharpening; aspect override and integer scaling; rotation in quarter turns; line doubling for 240p and 288p sources.

Crop is dragged on the picture, or found by Detect, which measures the black border as a union across about two seconds so a fade to black is not read as the picture getting smaller, and refuses when too little would survive: a GameCube home screen leaves 37 % of the area, against 57 % for the widest border that is still a border.

Colour range and matrix default to automatic, the range measured from the image rather than inferred from the pixel format — a console set to full range delivers full range whether the card is asked for NV12 or RGB32.

A native pixel grid setting resolves every output pixel to the console's own rather than to a fraction of one. A card samples the line at a fixed rate, usually 720, while a SNES draws 256 pixels across it, so the boundaries land wherever the arithmetic puts them; told the real count, the grid comes back. It recovers the grid, not the detail that grid carried — only sampling at the console's own dot clock does that, and nothing downstream of a capture card can.

Optional scanlines and a shadow mask, off by default and display only, each compensating its own brightness so the sliders change structure rather than exposure. Scanlines switch off below twice the source height, where there is nowhere to put a gap.

More: Scaling and sharpening, Cropping and geometry, Colour range and matrix.

Deinterlacing

Whether the source is interlaced is measured rather than believed — a media type is entitled to say so and frequently does not. The figures are vertical movement between consecutive frames, measured on a 480i console:

Mode Vertical movement
Off (weave) none combing on anything that moves
Bob 1.0 line full rate, no latency, no interpolation
Bob interpolated 0.56 the alternation between sharp and interpolated lines
Motion adaptive 0.005 weaves what is still, interpolates what is not
Edge directed 0.69 follows edges; meant for pixel art
YADIF 0.002 best quality; keeps one frame in memory

Left: a 480i GameCube frame woven, with combing across the moving item boxes. Right: the same source through YADIF, clean

More: Deinterlacing.

Composite

A composite signal carries colour and brightness on one wire, and the two leak into each other: dot crawl along colour edges, rainbow shimmer over fine detail.

Two controls address the dot crawl and hand over to each other. A four-frame average removes it wherever the picture stands still, at no cost in sharpness; a synchronous demodulator handles what is moving, reconstructing the colour subcarrier out of the brightness and subtracting it at some cost in horizontal sharpness. The averaging engages whenever the demodulator is used, so it never pays for what is already free. Its slider snaps to the steps that actually change the window width — nine on PAL — because the positions in between compute the same filter.

Avoid ghosting decides where the averaging lets go of movement. Averaging across movement is smearing, so this moves the trade rather than removing it: held on late, slow low-contrast movement drags a trail; released early, moving edges stay clean and slow areas keep some crawl for the demodulator.

Left: a GameCube over composite with the filter off, dot crawl speckling the gold laurel and the chequered flag. Right: the same frame with the filter on

Colour shimmer is handled separately, by averaging the colour sideways — which composite carries at a quarter of the bandwidth anyway. Each neighbour is weighted by how close its colour is to the centre's; an unweighted average across a colour edge turns complementary neighbours into grey.

The subcarrier frequency follows from the video standard, so the Source tab matters here too. SECAM is not handled by the demodulator; the averaging still applies.

More: The composite filter.

The Picture tab: scaling and sharpening, the deinterlacer, the composite filter with its two controls, and the crop with its Detect button

High dynamic range

P010 and P016 sources are read against either PQ (ST 2084) or HLG (BT.2100) and turned into linear light. An ordinary screen gets BT.2390 tone mapping; an HDR screen gets scRGB.

Recording, screenshots and the virtual camera each get the tone mapped picture by default, and each can be told to keep the range instead — ten bit P010 for a recording, JPEG XR or AVIF for a screenshot, ten bit P010 for the camera.

More: High dynamic range.

The HDR tab: source curve, what goes to the display, paper white and source peak, and the three switches for keeping the range — greyed out here, because the source was SDR

Audio

The card's embedded audio, or any Windows recording device, played out through WASAPI. The buffer target is configurable, exclusive mode is optional, and an A/V offset is available. Drift between the capture and playback clocks is corrected by nudging the playback rate by a fraction of a per cent.

An optional microphone is recorded as a separate input with its own gain, and is never played back. By default the file gets three tracks: a mix, plus the capture and microphone separately.

More: Audio.

Recording

H.264, H.265 or AV1 through NVENC, Quick Sync, AMF, x264 or x265, encoded by ffmpeg. The recording is made at source resolution, after crop and deinterlacing and before window scaling, so window size does not affect the result.

The capture audio serves as the master clock and the video timeline is derived from the number of audio samples written, so the output is constant frame rate and does not drift: measured at 1 ms over 15 seconds.

More: Recording.

Screenshots

Taken at source resolution, after crop and deinterlacing and before window scaling. The grab happens before the interface is drawn, so no overlay, toolbar or settings panel reaches the file. Include the interface moves it to after, saving the finished window instead — window-sized rather than source-sized, and always SDR.

SDR: PNG or JPEG. Both go through Windows Imaging Component, so no ffmpeg is needed. PNG is the default; JPEG has an adjustable quality.

HDR: JPEG XR or AVIF. When the source is HDR, a screenshot can keep the range instead of being mapped down to SDR first. The two are a genuine trade rather than a preference:

Needs Read by
JPEG XR (.jxr) nothing — Windows ships the encoder the Windows Photos app; little else
AVIF (.avif) ffmpeg, with libaom every browser, and most things that are not Windows

AVIF is the only part of screenshots that needs ffmpeg. Without it the setting says so and points at the download, rather than failing at the moment you press the key. The still is encoded as 10-bit AV1 on the PQ curve, tagged BT.2020 — without those tags a viewer reads the samples as ordinary SDR and shows a dark picture.

Whether HDR stills are written at all is a switch of its own under HDR, alongside the equivalents for recordings and the virtual camera.

More: Screenshots.

Encoder settings

Rate control, preset, tuning, look-ahead, adaptive quantisation and multipass are exposed under one set of names and translated into each vendor's own. Everything defaults to automatic, which passes nothing at all rather than passing the encoder's default. Anything a given encoder has no opinion about is greyed out rather than hidden.

More: Encoder settings.

The Encoder tab: ffmpeg at the top, then which encoder — naming the five that passed the test on this machine and the four that did not — and the settings it is given

Virtual camera

The picture can be offered to other programs as a webcam called CapView Virtual Camera, at the source's own resolution and the source's own frame rate. Not a list of sizes: a 240p SNES goes out as 240p, a 1080p60 Switch as 1080p60, and if you ever put 8K at 120 in front of it, that is what comes out.

Programs that cannot take that get one of the ordinary sizes below it -- 640x480 and the rest -- scaled and letterboxed inside their own process, at no cost to anything else reading the same camera. Every consumer negotiates for itself, and the settings page lists them by name while they read.

Nothing above the source is offered. A camera that advertises more than it has is a camera that misleads: the program picks the largest entry, keeps that choice for as long as it holds the camera, and goes on listing it after the console has changed. So a 576i console offers 576i and smaller, and a program wanting 1080p from it upscales at its own end, where that work belongs.

An HDR source is additionally offered as ten bit P010, with the eight bit form right behind it so that programs which have never heard of an HDR webcam still find something they understand.

The cost is a one-time install with a UAC prompt, because a DirectShow filter is registered machine-wide. There is an uninstall button next to it.

Being registered machine-wide also means the camera stays in every device list once installed, whether CapView is running or not -- the same as OBS's virtual camera. While nothing is feeding it, it shows a picture that says so instead of black.

A program settles its format once, when it opens the camera, and keeps it for as long as it holds it open. Swapping a 1080p console for a 576i one changes what CapView publishes straight away, but a program already reading goes on asking for the size it negotiated, so it keeps getting the new picture fitted into the old shape. Reopening the camera there picks the new size up.

Whatever program you read the camera with, leave its resolution on automatic and do not pick a size by hand. In OBS that is Resolution/FPS Type: Device Default; on Custom it asks for the size written in the box and nothing else, whatever the console is now doing. After changing console, disable the device and enable it again and OBS picks the new size up. Discord needs no more than the camera off and back on.

More: Virtual camera.

The Recording tab: container, bitrate, frame rate and output folder, with screenshots and the virtual camera below them

One profile per console

A profile holds everything: the device, the card input, the video standard, the capture format, and every picture and audio setting. Ctrl+1 to Ctrl+9 switch between them. This is how the program is meant to be used, and it is worth setting up before anything else.

Almost nothing carries over between consoles. A SNES over composite wants the four-frame average and the demodulator against dot crawl, a native width of 256, PAL at 625 lines and 50 Hz; a Switch over HDMI wants none of that and 1080p at 60. Set both up once and swapping a cable is one keystroke rather than a tour of the settings.

Save current as … turns whatever is set up right now into a profile, asking for a name with the cursor already in the field, so a second console is a matter of changing what is actually different rather than rebuilding what was already correct.

Settings that do not apply to the current source are not applied, not merely hidden. The values stay in the profile — that console will be back — but they are not restored on the way out and back, since the next analogue source may well be a different console.

Updates

Settings → Updates compares this build against the newest release on GitHub, either at startup or on request. Installing replaces CapView.exe itself, by renaming rather than overwriting, and a failed update leaves the program as it was rather than gone.

More: Updates.

Shortcuts

Key Action
Enter Fullscreen
Esc Leave fullscreen
F1 Statistics
F2 Settings
F5 Restart capture
F9 Start / stop recording
F10 Screenshot
M Mute
+ / - or mouse wheel Volume
Ctrl+1 … Ctrl+9 Switch profile
Right click Menu

All of these except Esc, the profile digits and Alt+F4 can be reassigned under Settings → Keys.

More: Shortcuts, The settings window.

Building

Requires Visual Studio 2022 with the Desktop C++ workload, and CMake. There are no external dependencies; Dear ImGui is vendored in third_party/.

build.bat

The result is CapView.exe in the repository root, about 2 MB, linked against the static CRT. build.bat keep retains the build tree for incremental rebuilds, and build.bat debug produces a debug configuration.

Settings are stored in CapView.json beside the executable; nothing is written to the registry. Prebuilt executables are attached to each release.

More: Building.

ffmpeg

Two things require ffmpeg.exe, and nothing else does:

  • Recording, whichever encoder is used.
  • HDR screenshots in AVIF, which go through libaom. The other HDR format, JPEG XR, does not — Windows ships that encoder — so an HDR still can be saved without ffmpeg by choosing it instead. SDR screenshots never need it.

The preview, the composite filters, deinterlacing and the virtual camera run without it.

Settings → Encoder provides a button that downloads a static build, verifies its published SHA-256 and extracts only the executable. The same is available from the command line:

CapView.exe --fetch-ffmpeg

Available encoders are determined by test-encoding two frames with each candidate, rather than by reading ffmpeg -encoders, which lists what the build was compiled with rather than what the hardware supports.

More: ffmpeg.

Limitations

  • A card grants its capture pin to one process at a time. If OBS holds it, CapView cannot open it, and the other way round.
  • The virtual camera is not visible to packaged apps. Its shared memory lives in the session namespace, which an app container cannot see -- so the Windows Camera app and Store builds of Teams do not find it. Everything that loads DirectShow normally does: OBS, Discord, browsers, vMix, XSplit.
  • The HDR display path is untested on real HDR hardware. The maths is checked against the standards and the tone mapped path is verified; the scRGB output has never been run against an HDR monitor.
  • SECAM dot crawl is only handled by the temporal half of the composite filter.

Why DirectShow

Capture cards that ship a Media Foundation driver also expose a DirectShow interface, since both sit on the same Kernel Streaming layer. The reverse does not hold: older and semi-professional cards are frequently DirectShow only. On the development machine, DirectShow enumerates five video devices where Media Foundation enumerates three.

Licence

CapView is MIT licensed. Dear ImGui is MIT licensed as well.

ffmpeg is a separate program, downloaded from upstream and executed as a child process. The usual Windows builds contain x264 and x265 and are therefore GPL licensed; invoking a program is not linking against it, so those terms do not extend to CapView. Redistributing CapView together with an ffmpeg build is a different matter, and the GPL then applies to what is being distributed.