split 0.1.0

Resource Split for BIN/IVF/WEBM/PSNR/YUV/...
Documentation
use std::fs::File;
use std::io;
use std::io::{Read, Write};
use std::io::{Error, ErrorKind};

pub struct Yuv {
    pub input_yuv: String,
    pub output_prefix: String,
    pub frame_num: usize,
    pub frame_size: Vec<(i32, i32)>,
}

impl Yuv {
    pub fn helper() {
        println!("Usage: split yuv input.yuv output_prefix frame_num frame_size1 [...|frame_size2 \
                  ...]")
    }

    pub fn new(args: &[String]) -> Result<Yuv, &'static str> {
        let l = args.len() as usize;
        if l < 6 {
            return Err("too less arguments for split yuv mode");
        }

        let input_yuv = args[2].clone();
        let output_prefix = args[3].clone();
        let frame_num_opt = args[4].clone().parse::<usize>();
        let frame_num = match frame_num_opt {
            Ok(frame_num) => frame_num,
            Err(_) => {
                return Err("can't parse frame_num as usize");
            }
        };

        let mut frame_size: Vec<(i32, i32)> = Vec::new();
        for i in 0..frame_num {
            if 5 + i >= l {
                return Err("too less arguments for split yuv mode");
            } else if args[5 + i] == "..." {
                if i == 0 {
                    return Err("... can't be the first frame size");
                } else {
                    let (width, height) = frame_size[i - 1];
                    for _ in i..frame_num {
                        frame_size.push((width, height));
                    }
                    break;
                }
            } else {
                let frame_size_str = args[5 + i].clone();
                let nums: Vec<&str> = frame_size_str.split("x").collect();
                if nums.len() != 2 {
                    return Err("invalid frame size");
                }
                if let Ok(width) = nums[0].parse::<i32>() {
                    if let Ok(height) = nums[1].parse::<i32>() {
                        frame_size.push((width, height));
                    } else {
                        return Err("invalid frame height");
                    }
                } else {
                    return Err("invalid frame width");
                }
            }
        }

        Ok(Yuv {
            input_yuv: input_yuv,
            output_prefix: output_prefix,
            frame_num: frame_num,
            frame_size: frame_size,
        })
    }

    pub fn run(&self) -> io::Result<()> {
        println!("Split {} into {}", self.input_yuv, self.output_prefix);
        let mut fi = try!(File::open(self.input_yuv.clone()));
        const BUF_SIZE: usize = 2048;
        let mut buf = [0u8; BUF_SIZE];

        for i in 0..self.frame_num {
            let output_yuv = self.output_prefix.clone() + "_" + &i.to_string() + "_" +
                             &self.frame_size[i].0.to_string() +
                             "x" + &self.frame_size[i].1.to_string() +
                             ".yuv";
            println!("Frame {} - {}x{} in {} ...",
                     i,
                     self.frame_size[i].0,
                     self.frame_size[i].1,
                     output_yuv);
            let mut buf_size = (self.frame_size[i].0 * self.frame_size[i].1 +
                                ((self.frame_size[i].0 + 1) / 2) *
                                ((self.frame_size[i].1 + 1) / 2) *
                                2) as usize;
            let mut fo = try!(File::create(output_yuv));
            while buf_size > 0 {
                let bytes = if buf_size > BUF_SIZE {
                    BUF_SIZE
                } else {
                    buf_size
                };
                buf_size -= bytes;
                let bytes_read = fi.read(&mut buf[0..bytes]).unwrap();
                if bytes_read != bytes {
                    return Err(Error::new(ErrorKind::Other, "bytes read is not expected ..."));
                }
                let bytes_write = fo.write(&buf[0..bytes]).unwrap();
                if bytes_write != bytes {
                    return Err(Error::new(ErrorKind::Other, "bytes write is not expected ..."));
                }
            }
        }

        Ok(())
    }
}