revc 0.1.3

Rust Essential Video Coding (MPEG-5 EVC)
Documentation
use std::fs::File;
use std::io;
use std::io::Read;

use super::*;
use revc::api::frame::*;
use revc::api::*;

pub struct YuvDemuxer {
    reader: Box<dyn Read>,
    info: Option<VideoInfo>,
}

impl YuvDemuxer {
    pub fn new(path: &str, info: Option<VideoInfo>) -> io::Result<Box<dyn Demuxer>> {
        Ok(Box::new(YuvDemuxer {
            reader: match path {
                "-" => Box::new(io::stdin()),
                f => Box::new(File::open(&f).unwrap()),
            },
            info,
        }))
    }
}

impl Demuxer for YuvDemuxer {
    fn read(&mut self) -> io::Result<Data> {
        if let Some(info) = &self.info {
            let bytes_per_sample = if info.bit_depth > 8 { 2 } else { 1 };
            let pitch_y = info.width * bytes_per_sample;
            let height = info.height;
            let chroma_sampling_period = info.chroma_sampling.sampling_period();
            let (pitch_uv, height_uv) = (
                (pitch_y * bytes_per_sample) / chroma_sampling_period.0,
                height / chroma_sampling_period.1,
            );

            let (mut rec_y, mut rec_u, mut rec_v) = (
                vec![128u8; pitch_y * height],
                vec![128u8; pitch_uv * height_uv],
                vec![128u8; pitch_uv * height_uv],
            );

            self.reader.read_exact(&mut rec_y)?;
            self.reader.read_exact(&mut rec_u)?;
            self.reader.read_exact(&mut rec_v)?;

            let mut frame: Frame<u16> = Frame::new(info.width, info.height, info.chroma_sampling);

            frame.planes[0].copy_from_raw_u8(&rec_y, pitch_y, bytes_per_sample);
            frame.planes[1].copy_from_raw_u8(&rec_u, pitch_uv, bytes_per_sample);
            frame.planes[2].copy_from_raw_u8(&rec_v, pitch_uv, bytes_per_sample);

            frame.planes[0].conv_8b_to_16b(2);
            frame.planes[1].conv_8b_to_16b(2);
            frame.planes[2].conv_8b_to_16b(2);

            Ok(Data::Frame(Some(frame)))
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Invalid VideoInfo for YuvDemuxer",
            ))
        }
    }

    fn info(&self) -> Option<VideoInfo> {
        self.info
    }
}