onix 0.1.0

Decode image files using V4L2
Documentation
mod error;
mod sw;
pub mod uapi;

use error::ImageResult;
use std::io::Read;
use sw::Vp8Decoder;

pub use uapi::CtrlVp8Frame;

const DEFAULT_MV_PROBS: [[u8; 19]; 2] = [
    [
        162, 128, 225, 146, 172, 147, 214, 39, 156, 128, 129, 132, 75, 145, 178, 206, 239, 254, 254,
    ],
    [
        164, 128, 204, 170, 119, 235, 140, 230, 228, 128, 130, 130, 74, 148, 180, 203, 236, 254,
        254,
    ],
];

/// VP8 Decoder
///
/// Only decodes keyframes
pub struct Parser<R: core::fmt::Debug> {
    sw: Vp8Decoder<R>,
}

impl<R: Read + core::fmt::Debug> Parser<R> {
    /// Create a new decoder.
    /// The reader must present a raw vp8 bitstream to the decoder
    pub fn new(r: R) -> Parser<R> {
        let sw = Vp8Decoder::new(r);
        Parser { sw }
    }

    pub fn parse_vp8(&mut self) -> ImageResult<CtrlVp8Frame> {
        assert_eq!(std::mem::size_of::<CtrlVp8Frame>(), 1232);

        self.sw.read_frame_header()?;

        assert_eq!(self.sw.num_partitions, 1);

        let quant_update = [
            self.sw.segment[0].quantizer_level,
            self.sw.segment[1].quantizer_level,
            self.sw.segment[2].quantizer_level,
            self.sw.segment[3].quantizer_level,
        ];
        let lf_update = [
            self.sw.segment[0].loopfilter_level,
            self.sw.segment[1].loopfilter_level,
            self.sw.segment[2].loopfilter_level,
            self.sw.segment[3].loopfilter_level,
        ];
        let mut flags = uapi::Vp8SegmentFlags::empty();
        if self.sw.segments_enabled {
            flags |= uapi::Vp8SegmentFlags::ENABLED;
        }
        if self.sw.segments_update_map {
            flags |= uapi::Vp8SegmentFlags::UPDATE_MAP;
        }
        if self.sw.update_segment_feature_data {
            flags |= uapi::Vp8SegmentFlags::UPDATE_FEATURE_DATA;
        }
        // TODO: Figure out why this gives a yellow tint to the image!
        //if self.sw.segment_feature_mode {
        //    flags |= uapi::Vp8SegmentFlags::DELTA_VALUE_MODE;
        //}
        let segment = uapi::v4l2_vp8_segment {
            quant_update,
            lf_update,
            segment_probs: self.sw.segment_tree_probs,
            padding: 0,
            flags,
        };

        let mut flags = uapi::Vp8LoopFilter::empty();
        if self.sw.lf_adjust_enable {
            flags |= uapi::Vp8LoopFilter::ADJ_ENABLE;
        }
        if self.sw.delta_update {
            flags |= uapi::Vp8LoopFilter::DELTA_UPDATE;
        }
        if self.sw.frame.filter_type {
            flags |= uapi::Vp8LoopFilter::FILTER_TYPE_SIMPLE;
        }
        let lf = uapi::v4l2_vp8_loop_filter {
            ref_frm_delta: self.sw.ref_delta,
            mb_mode_delta: self.sw.mode_delta,
            sharpness_level: self.sw.frame.sharpness_level,
            level: self.sw.frame.filter_level,
            padding: 0,
            flags,
        };

        let quant = uapi::v4l2_vp8_quantization {
            y_ac_qi: self.sw.quant.y_ac_qi,
            y_dc_delta: self.sw.quant.y_dc_delta,
            y2_dc_delta: self.sw.quant.y2_dc_delta,
            y2_ac_delta: self.sw.quant.y2_ac_delta,
            uv_dc_delta: self.sw.quant.uv_dc_delta,
            uv_ac_delta: self.sw.quant.uv_ac_delta,
            padding: 0,
        };

        let entropy = uapi::v4l2_vp8_entropy {
            coeff_probs: *self.sw.token_probs,
            y_mode_probs: sw::KEYFRAME_YMODE_PROBS,
            uv_mode_probs: sw::KEYFRAME_UV_MODE_PROBS,
            mv_probs: DEFAULT_MV_PROBS,
            padding: [0; 3],
        };

        let coder_state = uapi::v4l2_vp8_entropy_coder_state {
            range: self.sw.b.range as u8,
            value: self.sw.b.value as u8,
            bit_count: self.sw.b.bit_count,
            padding: 0,
        };

        let (mb_no_skip_coeff, prob_skip_false) =
            if let Some(prob_skip_false) = self.sw.prob_skip_false {
                (true, prob_skip_false)
            } else {
                (false, 0)
            };
        let mut flags = uapi::Vp8FrameFlags::empty();
        if self.sw.frame.keyframe {
            flags |= uapi::Vp8FrameFlags::KEY_FRAME;
        }
        if self.sw.frame.for_display {
            flags |= uapi::Vp8FrameFlags::SHOW_FRAME;
        }
        if mb_no_skip_coeff {
            flags |= uapi::Vp8FrameFlags::MB_NO_SKIP_COEFF;
        }
        Ok(CtrlVp8Frame {
            segment,
            lf,
            quant,
            entropy,
            coder_state,

            width: self.sw.frame.width,
            height: self.sw.frame.height,

            horizontal_scale: self.sw.frame.horizontal_scale,
            vertical_scale: self.sw.frame.vertical_scale,

            version: self.sw.frame.version,
            prob_skip_false,
            prob_intra: 0,
            prob_last: 0,
            prob_gf: 0,
            num_dct_parts: self.sw.num_partitions,

            first_part_size: self.sw.frame.first_partition_size,
            first_part_header_bits: 0,
            dct_part_sizes: [0, 0, 0, 0, 0, 0, 0, 0],

            last_frame_ts: 0,
            golden_frame_ts: 0,
            alt_frame_ts: 0,

            flags,
        })
    }
}