1use std::fs::File;
2use std::io;
3use std::io::Write;
4use std::io::{Error, ErrorKind};
5use std::ffi::CString;
6use std::os::raw::c_void;
7use std::slice;
8
9#[link(name = "nestegg")]
10extern "C" {
11 fn vpx_init(filename: *const i8) -> *mut c_void;
12 fn vpx_read(input: *mut c_void, length: *mut u32) -> *const u8;
13 fn vpx_destroy(input: *mut c_void);
14}
15
16pub struct Webm {
17 pub input: String,
18 pub output: String,
19 pub frame_num: usize,
20 pub vp9: bool,
21}
22
23impl Webm {
24 pub fn helper() {
25 println!("Usage: rsplit webm input.webm output.ivf frame_num vp8|vp9")
26 }
27
28 pub fn new(args: &[String]) -> Result<Webm, &'static str> {
29 let l = args.len() as usize;
30 if l < 6 {
31 return Err("too less arguments for rsplit webm mode");
32 }
33
34 let input = args[2].clone();
35 let output = args[3].clone();
36 let frame_num_opt = args[4].clone().parse::<usize>();
37 let frame_num = match frame_num_opt {
38 Ok(frame_num) => frame_num,
39 Err(_) => {
40 return Err("can't parse frame_num as usize");
41 }
42 };
43 let vp9 = match args[5].to_lowercase().as_ref() {
44 "vp9" => true,
45 "vp8" => false,
46 _ => {
47 return Err("only support vp8 and vp9");
48 }
49 };
50
51 Ok(Webm {
52 input: input,
53 output: output,
54 frame_num: frame_num,
55 vp9: vp9,
56 })
57 }
58
59 pub fn run(&self) -> io::Result<()> {
60 println!("Convert {} into {}", self.input, self.output);
61 let c_input_string =
62 unsafe { CString::from_vec_unchecked(self.input.clone().into_bytes()) };
63 let input_ctx = unsafe { vpx_init(c_input_string.as_ptr()) };
64
65 let mut fo = try!(File::create(self.output.clone()));
66 let mut ivf_seq_header = [0u8; 32];
67 let mut ivf_frame_header = [0u8; 12];
68
69 ivf_seq_header[0] = 'D' as u8;
70 ivf_seq_header[1] = 'K' as u8;
71 ivf_seq_header[2] = 'I' as u8;
72 ivf_seq_header[3] = 'F' as u8;
73 ivf_seq_header[4] = 0; ivf_seq_header[5] = 0; ivf_seq_header[6] = 32; ivf_seq_header[7] = 0; ivf_seq_header[8] = 'V' as u8; ivf_seq_header[9] = 'P' as u8; if self.vp9 {
80 ivf_seq_header[10] = '9' as u8; } else {
82 ivf_seq_header[10] = '8' as u8; }
84 ivf_seq_header[11] = '0' as u8; ivf_seq_header[12] = 0; ivf_seq_header[13] = 0; ivf_seq_header[14] = 0; ivf_seq_header[15] = 0; ivf_seq_header[16] = 0xE8; ivf_seq_header[17] = 0x03; ivf_seq_header[18] = 0x00; ivf_seq_header[19] = 0x00; ivf_seq_header[20] = 0x01; ivf_seq_header[21] = 0x00; ivf_seq_header[22] = 0x00; ivf_seq_header[23] = 0x00; ivf_seq_header[24] = ((self.frame_num >> 0) & 0xFF) as u8; ivf_seq_header[25] = ((self.frame_num >> 8) & 0xFF) as u8; ivf_seq_header[26] = ((self.frame_num >> 16) & 0xFF) as u8; ivf_seq_header[27] = ((self.frame_num >> 24) & 0xFF) as u8; ivf_seq_header[28] = 0; ivf_seq_header[29] = 0; ivf_seq_header[30] = 0; ivf_seq_header[31] = 0; let bytes_write = fo.write(&ivf_seq_header).unwrap();
107 if bytes_write != 32 {
108 return Err(Error::new(ErrorKind::Other, "bytes write is not expected ..."));
109 }
110
111 let mut frame_no = 0;
112 while frame_no < self.frame_num {
113 let mut len = 0;
114 let ptr = unsafe { vpx_read(input_ctx, &mut len) };
115 let buffer = unsafe { slice::from_raw_parts(ptr, len as usize) };
116
117 if len != 0 {
118 println!("Frame {:04}: {:8} bytes", frame_no, len);
119 } else {
120 break;
121 }
122 frame_no += 1;
123
124 ivf_frame_header[0] = ((len >> 0) & 0xFF) as u8; ivf_frame_header[1] = ((len >> 8) & 0xFF) as u8; ivf_frame_header[2] = ((len >> 16) & 0xFF) as u8; ivf_frame_header[3] = ((len >> 24) & 0xFF) as u8; let bytes_write = fo.write(&ivf_frame_header).unwrap();
129 if bytes_write != 12 {
130 return Err(Error::new(ErrorKind::Other, "bytes write is not expected ..."));
131 }
132 let bytes_write = fo.write(&buffer[0..(len as usize)]).unwrap();
133 if bytes_write != (len as usize) {
134 return Err(Error::new(ErrorKind::Other, "bytes write is not expected ..."));
135 }
136 }
137
138 unsafe { vpx_destroy(input_ctx) };
139
140 Ok(())
141 }
142}