2026-06-08 13:36:51 +05:30
# AsciiCam
2026-06-01 21:16:29 +05:30
2026-06-08 13:36:51 +05:30
Real-time ASCII video from your webcam in the terminal - pure C99, no heavy runtime dependencies.
2026-05-13 21:36:56 +05:30
2026-06-08 13:36:51 +05:30
< img src = "assets/demo.gif" width = "325" >
2026-05-13 21:36:56 +05:30
2026-06-08 13:36:51 +05:30
### Edge detection + threshold plugin
2026-05-30 21:19:15 +05:30
< img src = "assets/demo-edgedetection.gif" width = "325" >
2026-06-08 13:36:51 +05:30
---
## Features
| Feature | Details |
| ------------------------- | ------------------------------------------------------------------------------------- |
2026-06-17 15:54:08 +05:30
| **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` ) |
| **Cross‑ platform** | Linux (V4L2, nolibc) and macOS (AVFoundation, system libc) |
Linux: requires `gcc` , `linux/videodev2.h` (kernel headers), `libdl` , `libpthread` .
macOS: requires `Clang` and `AVFoundation` frameworks (linked automatically).
No other external dependencies.
2026-06-08 13:36:51 +05:30
---
## Build
```bash
2026-05-20 17:54:48 +05:30
git clone https://github.com/Harshit-Dhanwalkar/AsciiCam.git
cd AsciiCam/C/
make
```
2026-06-08 13:36:51 +05:30
Requires: `gcc` , `linux/videodev2.h` (kernel headers), `libdl` , `libpthread` .
No other external dependencies.
```
build/webcam_ascii --help
2026-05-26 17:47:36 +05:30
```
2026-06-08 13:36:51 +05:30
---
## Run
```bash
# Basic (grayscale, 80× 40, /dev/video0)
./build/webcam_ascii
# Truecolor output
./build/webcam_ascii -C
# With all three plugins
2026-05-26 17:47:36 +05:30
./build/webcam_ascii -p build/invert.so -p build/threshold.so -p build/edge_detect.so
2026-06-08 13:36:51 +05:30
# 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
2026-05-26 17:47:36 +05:30
```
2026-06-08 13:36:51 +05:30
---
2026-05-20 17:54:48 +05:30
2026-06-08 13:36:51 +05:30
## Plugin system
2026-05-13 21:36:56 +05:30
2026-06-08 13:36:51 +05:30
Plugins are shared objects (`.so` ).
2026-05-20 16:20:11 +05:30
2026-06-08 13:36:51 +05:30
```bash
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.
2026-05-30 20:47:23 +05:30
2026-06-08 13:36:51 +05:30
**Runtime controls:**
| Key | Action |
|---|---|
| `↑` / `↓` | select plugin |
| `[` / `]` | param $\pm$1 |
| `{` / `}` | param $\pm$10 |
| `r` | reset param to 128 |
| `q` | quit |
2026-05-31 17:15:53 +05:30
2026-05-31 17:26:49 +05:30
---
2026-05-31 17:15:53 +05:30
2026-06-08 13:36:51 +05:30
## TODO
- [x] Adjustable capture resolution
- [x] Producer/consumer thread split (double-buffered)
- [x] Brightness / contrast adjustment
- [x] Invert brightness to charset mapping
- [x] ANSI truecolor output
- [x] Floyd-Steinberg dithering
- [x] Sobel edge detection
- [x] SIMD YUYV to grayscale (SSE2)
- [x] Hot-reload plugin system
- [x] nolibc - zero libc calls
2026-06-17 15:54:08 +05:30
- [x] Custom charset via config file
2026-06-08 13:36:51 +05:30
- [ ] Record to `.mp4` / `.gif`
- [ ] Inter-frame delta compression
- [ ] LUT cache optimization
- [ ] Replace `pthread` with raw `futex` syscalls
- [ ] Replace `dlopen` with a minimal ELF loader
2026-06-17 15:54:08 +05:30
- [ ] Custom threading library using `clone()` + `futex` to eliminate `-lpthread` (`pthread` functions) dependency
- [ ] Implement an ELF loader (or statically link plugins) to eliminate `-ldl` (`dlopen` /`dlsym` /`dlclose` which are part of `libdl.so` also `glibc` ) dependency
- [x] MacOS support
- [ ] Color support for MacOS
- [ ] Windows support
2026-06-08 13:36:51 +05:30
2026-06-08 15:51:46 +05:30
## Fixes
2026-06-17 15:54:08 +05:30
- [x] [Issue #2 ](https://github.com/Harshit-Dhanwalkar/AsciiCam/issues/2 ) MacOS support
- [x] Rewrite `capture.c` for MacOS port using [AVFoundation ](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/04_MediaCapture.html ). ([Stackoverflow : how do I set up a video input using the AVFoundation framework ](https://stackoverflow.com/questions/32053460/how-do-i-set-up-a-video-input-using-the-avfoundation-framework ))
2026-06-08 15:51:46 +05:30
2026-06-08 13:36:51 +05:30
---
2026-05-31 19:21:05 +05:30
2026-06-08 13:36:51 +05:30
Project is under [PolyForm Noncommercial License BY-NC ](LICENCE ).
For commercial use contact *harshitpd1729@gmail.com* .