feat: complete `uninstall.sh` logic to make everything synced. feat: complete basic play logic to handle background, music, lyric play.
85 lines
3.2 KiB
C++
85 lines
3.2 KiB
C++
// backgroundDisplay.h
|
|
//
|
|
// Decode a video file (MP4 or any FFmpeg-supported container/codec) and play
|
|
// it in the terminal as truecolor ASCII art, honouring the video's aspect
|
|
// ratio.
|
|
//
|
|
// Terminal behaviour:
|
|
// - If the terminal can be resized programmatically ("adjustable"), the
|
|
// current width is kept and the height is set so the ASCII grid matches
|
|
// the video aspect ratio (terminal cells are roughly 2:1 tall:wide).
|
|
// - Otherwise the video is letterboxed to the largest size that fits the
|
|
// current terminal and the video frame size (e.g. "1280x720") is printed
|
|
// in the top-left corner of the terminal.
|
|
//
|
|
// This module is self-contained (raw ANSI escape sequences, no ncurses).
|
|
// Decoding runs on a background thread; playVideo() blocks the calling
|
|
// thread for the duration of playback, so callers can run several show
|
|
// components concurrently by using their own std::thread.
|
|
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <atomic>
|
|
|
|
#include "timeline.h"
|
|
|
|
namespace bd {
|
|
|
|
struct TermSize {
|
|
int cols = 0; // character columns
|
|
int rows = 0; // character rows
|
|
bool ok = false; // false when stdout is not a tty or the size is unknown
|
|
};
|
|
|
|
struct GridSize {
|
|
int cols = 0;
|
|
int rows = 0;
|
|
};
|
|
|
|
// --- terminal helpers -----------------------------------------------------
|
|
|
|
// True if stdout is an interactive terminal (isatty).
|
|
bool isTerminal();
|
|
|
|
// Current terminal size in character cells.
|
|
TermSize terminalSize();
|
|
|
|
// Ask the terminal to resize to (rows x cols) via the xterm sequence
|
|
// "\x1b[8;rows;colst" and verify it actually took effect (TIOCGWINSZ).
|
|
bool resizeTerminal(int rows, int cols);
|
|
|
|
// Probe whether the terminal honours programmatic resize requests. Restores
|
|
// the original size afterwards.
|
|
bool isTerminalAdjustable();
|
|
|
|
// Largest whole grid (cols x rows) with the video aspect ratio that fits
|
|
// inside (maxCols x maxRows). Rows are counted with 2:1 cell aspect.
|
|
GridSize fitSizeForAspect(int videoW, int videoH, int maxCols, int maxRows);
|
|
|
|
// --- video playback -------------------------------------------------------
|
|
|
|
struct PlayVideoOptions {
|
|
std::string path;
|
|
bool loop = false; // repeat the video until stop
|
|
float intensity = 1.0f; // brightness multiplier for fg/bg
|
|
bool tryResize = true; // false => force the "not adjustable" fit path
|
|
int topRows = 0; // reserve this many rows ABOVE the video (e.g. lyrics)
|
|
int bottomRows = 0; // reserve this many rows BELOW the video
|
|
GridSize* outGrid = nullptr; // receives the computed video grid (optional)
|
|
int* outOffsetX = nullptr; // receives the video's horizontal offset in cols
|
|
std::atomic<bool>* gridReady = nullptr; // set true once the layout is reported
|
|
std::atomic<bool>* stop = nullptr; // set to true to end playback early
|
|
};
|
|
|
|
// Play `path` as ASCII art, paced by `timeline` (may be null for an
|
|
// independent local clock). Blocks until the video ends (or `stop` is set).
|
|
// Returns:
|
|
// 0 playback finished (or stopped) cleanly
|
|
// 1 failed to open/decode the video
|
|
// 2 stdout is not a tty (nothing was written)
|
|
int playVideo(const std::string& path, Timeline* timeline,
|
|
const PlayVideoOptions& opts = {});
|
|
|
|
} // namespace bd
|