use std::{path::PathBuf, str::FromStr};
use crate::{
codec::Codec,
container::ContainerFormat,
errors::FfmpegError,
ffmpeg::{self, ChannelLayout, Stream},
};
use serde::{Deserialize, Serialize};
pub mod accessors;
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize, Serialize)]
pub struct MediaContainer {
path: PathBuf,
format: ContainerFormat,
stream: Stream,
duration: f32,
bit_rate: usize,
}
impl MediaContainer {
pub(crate) fn set_path(&mut self, path: PathBuf) {
self.path = path;
}
}
impl MediaContainer {
pub fn from_file(file: PathBuf) -> Result<Self, FfmpegError> {
#[derive(Deserialize)]
struct StreamRaw {
codec_name: String,
sample_rate: String,
channels: isize,
channel_layout: Option<String>,
duration: String,
}
#[derive(Deserialize)]
struct FormatRaw {
format_name: String,
duration: String,
bit_rate: String,
}
#[derive(Deserialize)]
struct Root {
streams: Vec<StreamRaw>,
format: FormatRaw,
}
let json = ffmpeg::ffprobe_media_container_json(&file)?;
let root: Root = serde_json::from_str(&json)?;
let raw_stream = root.streams.into_iter().next().ok_or_else(|| {
FfmpegError::FfprobeWrapperError("Input json contains no audio streams".to_owned())
})?;
Ok(Self {
path: file,
format: ContainerFormat::from_str(&root.format.format_name)
.map_err(FfmpegError::Other)?,
stream: Stream {
codec: Codec::from_str(&raw_stream.codec_name)
.map_err(|err| FfmpegError::Other(err.to_string()))?,
sample_rate: raw_stream
.sample_rate
.parse::<usize>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
channels: raw_stream.channels,
channel_layout: match raw_stream.channel_layout {
Some(ref s) => Some(ChannelLayout::from_str(s).map_err(FfmpegError::Other)?),
None => None,
},
duration: raw_stream
.duration
.parse::<f32>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
},
duration: root
.format
.duration
.parse::<f32>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
bit_rate: root
.format
.bit_rate
.parse::<usize>()
.map_err(|err| FfmpegError::Other(err.to_string()))?,
})
}
}