comparison src/main.rs @ 0:57b200fad67e

Hello world!
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Thu, 19 Nov 2020 21:31:36 +0100
parents
children 4adea0a8c8dd
comparison
equal deleted inserted replaced
-1:000000000000 0:57b200fad67e
1 use std::num::ParseIntError;
2 use std::str::FromStr;
3 use std::fmt;
4 use std::fs::File;
5 use std::io::{Read, BufReader, Seek, SeekFrom, Write, BufWriter};
6 use std::error::Error;
7 use std::env;
8 use std::process;
9
10 #[derive(Debug)]
11 pub enum ParseError {
12 Int(ParseIntError),
13 WrongResolution,
14 UnknownCodec,
15 Custom(String),
16 }
17
18 impl fmt::Display for ParseError {
19 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
20 write!(fmt, "{}", self)
21 }
22 }
23
24 impl Error for ParseError {}
25
26 impl From<ParseIntError> for ParseError {
27 fn from(e: ParseIntError) -> ParseError {
28 ParseError::Int(e)
29 }
30 }
31
32 #[derive(Debug)]
33 enum Codec {
34 H264,
35 }
36
37 impl FromStr for Codec {
38 type Err = ParseError;
39
40 fn from_str(s: &str) -> Result<Codec, ParseError> {
41 if s == "H.264" {
42 Ok(Codec::H264)
43 } else {
44 Err(ParseError::UnknownCodec)
45 }
46 }
47 }
48
49 #[derive(Debug, PartialEq)]
50 struct Resolution {
51 width: u16,
52 height: u16,
53 }
54
55 impl FromStr for Resolution {
56 type Err = ParseError;
57
58 fn from_str(s: &str) -> Result<Resolution, ParseError> {
59 let values: Vec<_> = s.split('x').collect();
60 if let [width, height] = values.as_slice() {
61 let width = width.parse()?;
62 let height = height.parse()?;
63 Ok(Resolution {
64 width,
65 height,
66 })
67 } else {
68 Err(ParseError::WrongResolution)
69 }
70 }
71 }
72
73 impl fmt::Display for Resolution {
74 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
75 write!(fmt, "{}×{}", self.width, self.height)
76 }
77 }
78
79 #[derive(Debug)]
80 pub struct VxSeekLine {
81 timestamp: u64,
82 video_name: String,
83 codec: Codec,
84 resolution: Resolution,
85 unknown: u8,
86 length: u32,
87 }
88
89 pub fn parse_vxseek(vxseek: &str) -> Result<Vec<VxSeekLine>, ParseError> {
90 let mut content = Vec::new();
91 for line in vxseek.lines() {
92 let fields: Vec<_> = line.split(':').collect();
93 match fields.as_slice() {
94 [timestamp, video_name, codec, resolution, unknown, length] => {
95 let timestamp = timestamp.parse()?;
96 let video_name = video_name.to_string();
97 let codec = codec.parse()?;
98 let resolution = resolution.parse()?;
99 let unknown = unknown.parse()?;
100 let length = length.parse()?;
101 content.push(VxSeekLine {
102 timestamp,
103 video_name,
104 codec,
105 resolution,
106 unknown,
107 length,
108 });
109 }
110 _ => return Err(ParseError::Custom(String::from("Invalid line in vxseek"))),
111 }
112 }
113 Ok(content)
114 }
115
116 fn main() -> Result<(), Box<dyn Error>> {
117 let args: Vec<_> = env::args().collect();
118 if args.len() != 5 {
119 eprintln!("Usage: {} <input.vxseek> <input.vxvideo> <resolution> <output.h264>", args[0]);
120 process::exit(1);
121 }
122 let vxseek_filename = &args[1];
123 let vxvideo_filename = &args[2];
124 let wanted_resolution: Resolution = args[3].parse()?;
125 let output_filename = &args[4];
126
127 let vxseek = {
128 let mut vxseek = File::open(vxseek_filename).unwrap();
129 let mut contents = String::new();
130 vxseek.read_to_string(&mut contents).unwrap();
131 parse_vxseek(&contents).unwrap()
132 };
133 {
134 let vxvideo = File::open(vxvideo_filename).unwrap();
135 let mut vxvideo = BufReader::new(vxvideo);
136
137 let output = File::create(output_filename).unwrap();
138 let mut output = BufWriter::new(output);
139
140 let mut name: Option<String> = None;
141 for VxSeekLine { timestamp, video_name, codec, resolution, unknown, length } in vxseek {
142 if let Some(ref name) = &name {
143 if &video_name != name {
144 vxvideo.seek(SeekFrom::Current(length as i64)).unwrap();
145 continue;
146 }
147 } else {
148 if resolution != wanted_resolution {
149 println!("Skipping {} due to resolution {}", video_name, resolution);
150 vxvideo.seek(SeekFrom::Current(length as i64)).unwrap();
151 continue;
152 }
153 name = Some(video_name);
154 }
155 let mut buf = Vec::with_capacity(length as usize);
156 unsafe { buf.set_len(length as usize) };
157 vxvideo.read_exact(&mut buf).unwrap();
158 output.write_all(&buf).unwrap();
159 output.flush().unwrap();
160 }
161 }
162 Ok(())
163 }