| assets | ||
| C | ||
| Cpp | ||
| tests | ||
| .gitignore | ||
| LICENCE | ||
| README.md | ||
AsciiCam
Real-time ASCII video from your webcam in the terminal - pure C99, no heavy runtime dependencies.
Edge detection + threshold plugin
Features
| Feature | Details |
|---|---|
| YUYV to grayscale | SSE2 SIMD (yuyv_to_gray_simd) - 16 pixels per iteration on x86_64, NEON on ARM64 |
| YUYV to RGB | Fixed‑point BT.601 conversion for truecolor output |
| Multiple render modes | Braille (⠿), Blocks (█ ░), ASCII ramp, Half‑block, Dots - switch live with m/M |
| Edge detection | Sobel, Sobel with direction, Laplacian - toggle with x/X |
| Hot‑reloadable charsets | Load .txt ramps from a directory, switch with n/N, monitor with inotify |
| Pseudo‑3D depth pop | Parallax effect based on brightness - adjust with +/-/v |
| Floyd‑Steinberg dither | Error‑diffusion to reduce banding |
| ANSI truecolor | \033[38;2;R;G;Bm per‑cell coloring |
| Hot‑reload plugin system | inotify + dlopen - rebuild a filter .so, it reloads live |
| FPS‑capped render loop | CLOCK_MONOTONIC + nanosleep frame pacing |
| Producer/consumer threads | Double‑buffered capture + render (stubbed in main loop, active in thread_sharing.c) |
| Hardware camera controls | V4L2 exposure, contrast, white-balance via ioctl — live keys e/E, c/C, w/W (Linux only; macOS/Windows display n/a) |
| Cross‑platform | Linux (V4L2, nolibc), macOS (AVFoundation, system libc), Windows (Media Foundation) |
Linux: requires gcc, linux/videodev2.h (kernel headers), libdl, libpthread.
macOS: requires Clang and AVFoundation frameworks (linked automatically).
Windows: requires MinGW-w64; links mfplat, mf, mfreadwrite, mfuuid, ole32 (Media Foundation). See Makefile windows branch.
No other external dependencies.
Build
git clone https://github.com/Harshit-Dhanwalkar/AsciiCam.git
cd AsciiCam/C/
make
Requires: gcc, linux/videodev2.h (kernel headers), libdl, libpthread.
No other external dependencies.
build/webcam_ascii --help
Run
# Basic (grayscale, 80×40, /dev/video0)
./build/webcam_ascii
# Truecolor output
./build/webcam_ascii -C
# With all three plugins
./build/webcam_ascii -p build/invert.so -p build/threshold.so -p build/edge_detect.so
# Edge detection mode, custom resolution
./build/webcam_ascii -e -w 320 -h 240 -W 120 -H 50
# Dithering + inverted charset
./build/webcam_ascii -D -i
Plugin system
Plugins are shared objects (.so).
gcc -O2 -fPIC -shared -Iinclude filters/my_filter.c -o build/my_filter.so
./build/webcam_ascii -p build/my_filter.so
Hot-reload: the binary watches the .so with inotify. Recompile it while the viewer is running and it reloads automatically within $\approx$100 ms.
Runtime controls:
| Key | Action |
|---|---|
m / M |
cycle render mode forward / backward |
x / X |
cycle edge detection mode forward / backward |
n / N |
cycle loaded charset forward / backward |
p / o |
increase / decrease depth-pop strength |
e / E |
hw exposure down / up (V4L2, Linux only) |
w / W |
hw white-balance down / up (V4L2, Linux only) |
c / C |
hw contrast down / up (V4L2, Linux only) |
↑ / ↓ |
select plugin |
[ / ] |
param $\pm$1 |
{ / } |
param $\pm$10 |
r |
reset param to 128 |
q |
quit |
TODO
- Adjustable capture resolution
- Producer/consumer thread split (double-buffered)
- Brightness / contrast adjustment
- Invert brightness to charset mapping
- ANSI truecolor output
- Floyd-Steinberg dithering
- Sobel edge detection
- SIMD YUYV to grayscale (SSE2)
- Hot-reload plugin system
- nolibc - zero libc calls
- Custom charset via config file
- Hardware camera controls (V4L2 exposure / contrast / white-balance)
- MacOS support
- Windows support (Media Foundation capture backend)
- Windows console raw-mode and signal handling (
SetConsoleMode/SetConsoleCtrlHandler) - Hardware controls via
IAMCameraControl/IAMVideoProcAmp(capture works, controls stubbed) - macOS hardware controls via
AVCaptureDeviceexposure/white-balance APIs (capture works, controls stubbed)
- Windows console raw-mode and signal handling (
- Cature frame resizing
- Record to
.mp4/.gif - Inter-frame delta compression
- LUT cache optimization
- Replace
pthreadwith rawfutexsyscalls - Replace
dlopenwith a minimal ELF loader - Custom threading library using
clone()+futexto eliminate-lpthreaddependency - Implement an ELF loader (or statically link plugins) to eliminate
-ldldependency- Color support for MacOS
Fixes
- Issue #2 MacOS support
- Rewrite
capture.cfor MacOS port using AVFoundation.
- Rewrite
nl_calloc: zero-fill loop was commented out (returned uninitialized memory) and theSIZE_MAXoverflow guard ran after the allocation, leaking the spurious block on overflow. Both fixed.nl_free: backward coalescing was aTODOstub — non-LIFO frees (e.g. edge-detection scratch buffers) left permanently unmerged holes. Implemented by walking from arena start to find the preceding block.main.cdouble-buffer bug: a secondout_bufwasmalloc/free'd every frame inside the loop, shadowing the persistent pre-loop allocation. Frame-loop malloc removed; the single persistent buffer is reused for the program's lifetime.ascii.cRENDER_HALF_BLOCKheight rounding:safe_dst_hwas rounded down to a multiple of 4 unconditionally, but half-block mode only needs multiples of 2 (it stacks 2 subpixel rows per glyph, not 4). Fixed to be mode-aware.
Project is under PolyForm Noncommercial License BY-NC. For commercial use contact harshitpd1729@gmail.com.