#Live streaming

Run commands from the repository root. Use a local source file first; URLs additionally need the yt-dlp extra and may be normalized to a lower frame rate. A 60 FPS ceiling cannot create frames absent from the source.

#Python quick start

python -m pip install .
python stream_server.py video.mp4 --mode 6 --cols 160

Open http://localhost:8000/. Python is the default engine. FFmpeg is needed for audio extraction and thumbnails. Video uses Canvas; audio uses an HTML audio element and browser playback policy. Click Play or Enable audio when needed.

#Rust pixel + DCT

Build Rust using the native installation guide, then use the configuration verified in the maintainer's playback test:

python stream_server.py video.mp4 --engine rust --pixel --pixel-codec dct --cols 450 --fps 60 --no-thumbnails --decode-ahead 3

Open http://localhost:8000/ or http://localhost:8000/static/examples/sdk-live.html. The latter imports the local SDK. This is a tested starting configuration, not a new default. Engine, effective FPS and coded grid are printed on connection.

A 1280x720 source with 450 requested columns has a 450x253 base pixel grid. DCT aligns it to 464x256. This aligned grid is actually encoded/drawn, not cropped back to 450 afterwards. To compare raw pixels, change only the codec to --pixel-codec raw.

Raw pixels avoid DCT reconstruction but send more data: at 450x253 and 60 FPS, BGR payload alone is about 20.5 MB/s (decimal), excluding packet/transport overhead. DCT introduces lossy reconstruction and work on server and client for a smaller content-dependent payload.

#Engine, mode and codec

Choice Values Responsibility
Engine python, rust, auto Source decoder and server processing
Representation --mode 1..6, --pixel Characters/colors or BGR pixels
Pixel transport --pixel-codec raw, dct Full pixel bytes or tag-4 prediction/DCT

rust fails explicitly if unavailable. auto allows Python fallback with a reason in the log. Webcam device input uses Python/OpenCV even when the file engine is Rust. The SDK receives the negotiated representation and codec; it needs no engine option.

ASCII mode Nominal colors Representation
1 Monochrome Frame index and newline-separated text
2 64 Character byte + RGB bytes per cell
3 512 Character byte + RGB bytes per cell
4 32,768 Character byte + RGB bytes per cell
5 262,144 Character byte + RGB bytes per cell
6 16,777,216 Character byte + RGB bytes per cell

Modes 2–6 quantize values but still store four bytes per cell before compression. ASCII uses Canvas text drawing. Pixel mode converts BGR to RGBA and calls putImageData; it draws no glyphs. DCT applies only to pixel mode.

#Defaults and flags

Option Default Effect
--engine python Explicit engine or fallback with auto
--mode 1 ASCII color mode; pixel promotes mode 1 to mode 6
--cols ASCII 200; pixel 450 Requested grid width
--rows 0 (automatic) Height from source and representation
--fps ASCII 30; Python pixel 30; Rust pixel 60 FPS ceiling, not interpolation
--pixel-codec raw DCT requires pixel and capable client
--dct-quality 70 Integer 1–100; lower is smaller/lossier
--quality lossless Adaptive ASCII color tolerance
--decode-ahead 0 Source queue: 0, 2, 3
--decode-threads omitted Codec default; 0 auto, 1..64 requested
--no-resolution-limit / --no-limit off Disable automatic grid performance caps
--no-thumbnails off Disable root-player hover previews
--debug off Bandwidth, production and client timing logs
--perf-record DIR off Session events and timing JSONL
--host, --port 127.0.0.1, 8000 Bind address and port

Automatic rows retain 125,000-pixel/12,000-ASCII-cell caps plus row/portrait rules. Requested columns may be reduced: the 1280x720 pixel example with --cols 750 becomes 471x265, or 750x422 with --no-resolution-limit, before DCT alignment. Explicit rows retain supplied dimensions. The override preserves FPS/native allocation checks. Alignment can add cells beyond the base-grid cap.

Sampling keeps every Nth source frame with N = ceil(source_fps / fps_limit), at least one. A 59.94 source becomes 29.97 under a 30 ceiling; 50 becomes 25. Lower-rate sources are not interpolated. Mode switches recalculate the default FPS; explicit --fps persists. Large ASCII grids can be browser text-drawing limited.

--quality high|balanced|low controls ASCII temporal color tolerance and is rejected with pixel playback. Use --dct-quality for DCT. Even quality 100 is lossy, including chroma subsampling.

#Capability and predictor

DCT requires server codec dct, active pixel file playback, and client query codec=adaptive&sync=1&pixel_codec=dct-v1. The local SDK and root demo advertise this. Older clients receive legacy/raw. Inspect SDK init.pixelCodec and the server [DCT] line to know the active transport.

Each session owns a predictor, reset on seek/reinit with a fresh keyframe. Encoding stays ordered. Source decoding, ASCILINE encoding and browser decoding are separate; Rust accelerates the first two and client reconstruction stays JavaScript. Rust/DCT CLI sessions disable WebSocket permessage-deflate; DCT packets already contain zlib compression.

#Source queue and decoder threads

--decode-ahead 3 creates one source worker only for Rust pixel files, RAW or DCT. It holds at most three prepared/in-progress frames plus the frame being encoded. Three 464x256 BGR payloads are about 1.02 MiB, excluding decoder/array overhead.

The worker owns source reads. Pause fills only the bounded queue. Seek, resize and release stop/join it before repositioning and starting a new queue. It stores no encoded packets or predictors. It overlaps work rather than making source decode cheaper.

--decode-threads 2 requests two FFmpeg source-decoder threads; 0 requests automatic selection. Actual workers are codec-specific. Omission preserves the default. Python/webcam inputs reject the override. This is independent of queue capacity and DCT encoding; more workers may compete with encoding. Compare timings before choosing.

#Python application API

from asciline import AsciiStreamServer
server = AsciiStreamServer(
    source="video.mp4", engine="rust", pixel=True,
    pixel_codec="dct", dct_quality=70, cols=450, fps=60,
    loop=False, thumbnails=False,
)
server.start()

The helper supports engine, representation, grid, FPS, codec, DCT quality and resolution override. Its constructor does not expose decode_ahead, decode_threads or perf_record; use CLI for these. Its defaults differ from CLI: mode 2, loop on, thumbnails off. Do not assume identical source-queue policy.

#Troubleshooting

For a freeze, correlate server delivery, decode backlog, rendered count and clock progress. BUF: 0 alone can be healthy just-in-time delivery. Record the real session using the performance guide.

For black SDK output, serve modules over HTTP and copy all src/, including live-session.js. If DCT is unexpectedly raw, inspect capability and INIT. If Rust video works but audio fails, check its recorded FFmpeg runtime and the /audio diagnostics. Keep tabs foreground when measuring visible FPS.