revc 0.1.3

Rust Essential Video Coding (MPEG-5 EVC)
Documentation
use super::{Demuxer, VideoInfo};
use crate::{map_y4m_error, Data};

use std::fs::File;
use std::io;
use std::io::Read;

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

pub struct Y4mDemuxer {
    reader: y4m::Decoder<Box<dyn Read>>,
}

impl Y4mDemuxer {
    pub fn new(path: &str) -> io::Result<Box<dyn Demuxer>> {
        let reader: Box<dyn Read> = match path {
            "-" => Box::new(io::stdin()),
            f => Box::new(File::open(&f).unwrap()),
        };

        Ok(Box::new(Y4mDemuxer {
            reader: y4m::Decoder::new(reader).map_err(|e| map_y4m_error(e))?,
        }))
    }
}

impl Demuxer for Y4mDemuxer {
    fn read(&mut self) -> io::Result<Data> {
        let width = self.reader.get_width();
        let height = self.reader.get_height();
        let bytes = self.reader.get_bytes_per_sample();
        let color_space = self.reader.get_colorspace();
        let chroma_sampling = map_y4m_color_space(color_space);
        let (xdec, _) = chroma_sampling.sampling_period();
        let chroma_width = (width + 1) >> xdec;
        let frame = self
            .reader
            .read_frame()
            .map(|frame| {
                let mut f: Frame<u16> = Frame::new(width, height, chroma_sampling);

                f.planes[0].copy_from_raw_u8(frame.get_y_plane(), width * bytes, bytes);
                f.planes[1].copy_from_raw_u8(frame.get_u_plane(), chroma_width * bytes, bytes);
                f.planes[2].copy_from_raw_u8(frame.get_v_plane(), chroma_width * bytes, bytes);

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

                f
            })
            .map_err(|e| map_y4m_error(e))?;

        Ok(Data::Frame(Some(frame)))
    }

    fn info(&self) -> Option<VideoInfo> {
        let width = self.reader.get_width();
        let height = self.reader.get_height();
        let color_space = self.reader.get_colorspace();
        let bit_depth = color_space.get_bit_depth();
        let chroma_sampling = map_y4m_color_space(color_space);
        let framerate = self.reader.get_framerate();
        let time_base = Rational::new(framerate.den as u64, framerate.num as u64);

        Some(VideoInfo {
            width,
            height,
            bit_depth,
            chroma_sampling,
            time_base,
        })
    }
}

fn map_y4m_color_space(color_space: y4m::Colorspace) -> ChromaSampling {
    use crate::ChromaSampling::*;
    use y4m::Colorspace::*;
    match color_space {
        Cmono => Cs400,
        C420jpeg | C420paldv => Cs420,
        C420mpeg2 => Cs420,
        C420 | C420p10 | C420p12 => Cs420,
        C422 | C422p10 | C422p12 => Cs422,
        C444 | C444p10 | C444p12 => Cs444,
    }
}