use std::{
fs::{File, OpenOptions},
io::{self, Write},
path::Path,
thread::sleep,
time::{Duration, SystemTime},
};
use indicatif::ProgressBar;
use opencv::prelude::*;
use opencv::{core, imgproc, videoio};
use terminal_size::{terminal_size, Height, Width};
use crate::converter;
use crate::error::{Error, Result};
pub fn render_to_file(fin: &Path, fout: &Path, strategy: converter::Strategy) -> Result<()> {
let mut capture = videoio::VideoCapture::from_file(fin.to_str().unwrap(), 0)?;
let frame_count: u64 = capture.get(videoio::CAP_PROP_FRAME_COUNT)? as u64;
let pb = ProgressBar::new(frame_count);
File::create(fout)?.write_all(
"#!/bin/bash\n# This file was auto-generated by asciiframe\necho -en '\033[2J' \n"
.as_bytes(),
)?;
for _i in 0..frame_count {
let mut frame = Mat::default();
capture.read(&mut frame)?;
let mut resized = Mat::default();
if let Some((Width(w), Height(h))) = terminal_size() {
imgproc::resize(
&frame,
&mut resized,
core::Size {
width: i32::from(w - 1),
height: i32::from(h - 1),
},
0.0,
0.0,
imgproc::INTER_AREA,
)?;
render_frame_to_file(&resized, strategy, fout)?;
pb.inc(1);
} else {
return Err(Error::from("Unable to get terminal size"));
}
}
Ok(())
}
pub fn render_to_stdout(fin: &Path, strategy: converter::Strategy) -> Result<()> {
let mut capture = videoio::VideoCapture::from_file(fin.to_str().unwrap(), 0)?;
let frame_count: u64 = capture.get(videoio::CAP_PROP_FRAME_COUNT)? as u64;
let time_d: f32 = (1.0 / capture.get(videoio::CAP_PROP_FPS)?) as f32;
let stdout = io::stdout();
let mut handle = stdout.lock();
for _i in 0..frame_count {
let start = SystemTime::now();
let mut frame = Mat::default();
capture.read(&mut frame)?;
let mut resized = Mat::default();
if let Some((Width(w), Height(h))) = terminal_size() {
imgproc::resize(
&frame,
&mut resized,
core::Size {
width: i32::from(w - 1),
height: i32::from(h - 1),
},
0.0,
0.0,
imgproc::INTER_AREA,
)?;
render_frame_stdout(&mut handle, &resized, strategy)?;
let elapsed = start.elapsed().unwrap().as_secs_f32();
if elapsed < time_d {
sleep(Duration::from_millis(((time_d - elapsed) * 1000.0) as u64));
}
} else {
return Err(Error::from("Unable to get terminal size"));
}
}
Ok(())
}
fn render_frame_stdout(
handle: &mut io::StdoutLock<'_>,
frame: &Mat,
strategy: converter::Strategy,
) -> Result<()> {
write!(handle, "{esc}c", esc = 27 as char)?;
write!(handle, "{}", converter::convert_frame(frame, strategy)?)?;
Ok(())
}
fn render_frame_to_file(frame: &Mat, strategy: converter::Strategy, path: &Path) -> Result<()> {
let mut fout = OpenOptions::new().append(true).open(path)?;
fout.write_all(
format!(
"echo '{}'\nsleep 0.033\necho '\u{001b}[0;0H' \n",
converter::convert_frame(frame, strategy)?
)
.as_bytes(),
)?;
Ok(())
}