use std::{path::Path, process::Command};
use crate::{
errors::FfmpegError,
ffmpeg::{command_mutators::FfmpegPresets, output_ffmpeg_err},
};
use lunar_lib::paths::sys::null_path;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Copy)]
pub struct LoudnormAnalysis {
pub(crate) input_i: f32,
pub(crate) input_tp: f32,
pub(crate) input_lra: f32,
pub(crate) input_thresh: f32,
}
impl LoudnormAnalysis {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, FfmpegError> {
#[derive(Deserialize, Debug, Clone, PartialEq, PartialOrd)]
struct Root {
pub input_i: String,
pub input_tp: String,
pub input_lra: String,
pub input_thresh: String,
pub output_i: String,
pub output_tp: String,
pub output_lra: String,
pub output_thresh: String,
pub normalization_type: String,
pub target_offset: String,
}
let mut command = Command::new("ffmpeg");
command.arg("-hide_banner");
command.input_file(path);
command.args(["-filter:a", "loudnorm=print_format=json", "-f", "null"]);
command.arg(null_path());
let result = output_ffmpeg_err(command)?;
let json_start = result.find('{').ok_or(FfmpegError::FfmpegWrapperError(
"Failed to find json start".to_string(),
))?;
let json_end = result.rfind('}').ok_or(FfmpegError::FfmpegWrapperError(
"Failed to find json end".to_string(),
))?;
let json_slice = &result[json_start..=json_end];
let root: Root = serde_json::from_str(json_slice)?;
let result = Self {
input_i: root
.input_i
.parse::<f32>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
input_tp: root
.input_tp
.parse::<f32>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
input_lra: root
.input_lra
.parse::<f32>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
input_thresh: root
.input_thresh
.parse::<f32>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
};
Ok(result)
}
}