# HG changeset patch # User Emmanuel Gil Peyrot # Date 1605817896 -3600 # Node ID 57b200fad67ee37241efd30499757d1bdc5c1ba2 Hello world! diff --git a/.hgignore b/.hgignore new file mode 100644 --- /dev/null +++ b/.hgignore @@ -0,0 +1,1 @@ +^target/ diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "vxvideo" +version = "0.1.0" +authors = ["Emmanuel Gil Peyrot "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,163 @@ +use std::num::ParseIntError; +use std::str::FromStr; +use std::fmt; +use std::fs::File; +use std::io::{Read, BufReader, Seek, SeekFrom, Write, BufWriter}; +use std::error::Error; +use std::env; +use std::process; + +#[derive(Debug)] +pub enum ParseError { + Int(ParseIntError), + WrongResolution, + UnknownCodec, + Custom(String), +} + +impl fmt::Display for ParseError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", self) + } +} + +impl Error for ParseError {} + +impl From for ParseError { + fn from(e: ParseIntError) -> ParseError { + ParseError::Int(e) + } +} + +#[derive(Debug)] +enum Codec { + H264, +} + +impl FromStr for Codec { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + if s == "H.264" { + Ok(Codec::H264) + } else { + Err(ParseError::UnknownCodec) + } + } +} + +#[derive(Debug, PartialEq)] +struct Resolution { + width: u16, + height: u16, +} + +impl FromStr for Resolution { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + let values: Vec<_> = s.split('x').collect(); + if let [width, height] = values.as_slice() { + let width = width.parse()?; + let height = height.parse()?; + Ok(Resolution { + width, + height, + }) + } else { + Err(ParseError::WrongResolution) + } + } +} + +impl fmt::Display for Resolution { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}×{}", self.width, self.height) + } +} + +#[derive(Debug)] +pub struct VxSeekLine { + timestamp: u64, + video_name: String, + codec: Codec, + resolution: Resolution, + unknown: u8, + length: u32, +} + +pub fn parse_vxseek(vxseek: &str) -> Result, ParseError> { + let mut content = Vec::new(); + for line in vxseek.lines() { + let fields: Vec<_> = line.split(':').collect(); + match fields.as_slice() { + [timestamp, video_name, codec, resolution, unknown, length] => { + let timestamp = timestamp.parse()?; + let video_name = video_name.to_string(); + let codec = codec.parse()?; + let resolution = resolution.parse()?; + let unknown = unknown.parse()?; + let length = length.parse()?; + content.push(VxSeekLine { + timestamp, + video_name, + codec, + resolution, + unknown, + length, + }); + } + _ => return Err(ParseError::Custom(String::from("Invalid line in vxseek"))), + } + } + Ok(content) +} + +fn main() -> Result<(), Box> { + let args: Vec<_> = env::args().collect(); + if args.len() != 5 { + eprintln!("Usage: {} ", args[0]); + process::exit(1); + } + let vxseek_filename = &args[1]; + let vxvideo_filename = &args[2]; + let wanted_resolution: Resolution = args[3].parse()?; + let output_filename = &args[4]; + + let vxseek = { + let mut vxseek = File::open(vxseek_filename).unwrap(); + let mut contents = String::new(); + vxseek.read_to_string(&mut contents).unwrap(); + parse_vxseek(&contents).unwrap() + }; + { + let vxvideo = File::open(vxvideo_filename).unwrap(); + let mut vxvideo = BufReader::new(vxvideo); + + let output = File::create(output_filename).unwrap(); + let mut output = BufWriter::new(output); + + let mut name: Option = None; + for VxSeekLine { timestamp, video_name, codec, resolution, unknown, length } in vxseek { + if let Some(ref name) = &name { + if &video_name != name { + vxvideo.seek(SeekFrom::Current(length as i64)).unwrap(); + continue; + } + } else { + if resolution != wanted_resolution { + println!("Skipping {} due to resolution {}", video_name, resolution); + vxvideo.seek(SeekFrom::Current(length as i64)).unwrap(); + continue; + } + name = Some(video_name); + } + let mut buf = Vec::with_capacity(length as usize); + unsafe { buf.set_len(length as usize) }; + vxvideo.read_exact(&mut buf).unwrap(); + output.write_all(&buf).unwrap(); + output.flush().unwrap(); + } + } + Ok(()) +}