terminal_video/
terminal_video.rs

1use anyhow::Result;
2use ffmpeg_sidecar::command::FfmpegCommand;
3
4const OUTPUT_WIDTH: u32 = 80;
5const OUTPUT_HEIGHT: u32 = 30;
6const OUTPUT_FRAMERATE: u32 = 60;
7
8/// Render video to the terminal
9fn main() -> Result<()> {
10  let iter = FfmpegCommand::new()
11    .format("lavfi")
12    .arg("-re") // "realtime"
13    .input(format!(
14      "testsrc=size={OUTPUT_WIDTH}x{OUTPUT_HEIGHT}:rate={OUTPUT_FRAMERATE}"
15    ))
16    .rawvideo()
17    .spawn()?
18    .iter()?
19    .filter_frames();
20
21  for frame in iter {
22    // clear the previous frame
23    if frame.frame_num > 0 {
24      for _ in 0..frame.height {
25        print!("\x1B[{}A", 1);
26      }
27    }
28
29    // Print the pixels colored with ANSI codes
30    for y in 0..frame.height {
31      for x in 0..frame.width {
32        let idx = (y * frame.width + x) as usize * 3;
33        let r = frame.data[idx] as u32;
34        let g = frame.data[idx + 1] as u32;
35        let b = frame.data[idx + 2] as u32;
36        print!("\x1B[48;2;{r};{g};{b}m ");
37      }
38      println!("\x1B[0m");
39    }
40  }
41
42  Ok(())
43}