wav1c 0.2.0

Wondrous AV1 encoder written in safe Rust.
Documentation
use crate::bitwriter::BitWriter;

fn bits_needed(v: u32) -> u8 {
    if v == 0 {
        1
    } else {
        32 - v.leading_zeros() as u8
    }
}

pub fn encode_sequence_header(width: u32, height: u32) -> Vec<u8> {
    let mut w = BitWriter::new();

    let seq_profile = 0u64;
    let still_picture = false;
    let reduced_still_picture_header = false;
    let timing_info_present = false;
    let initial_display_delay_present = false;
    let operating_points_cnt_minus_1 = 0u64;
    let operating_point_idc = 0u64;
    let seq_level_idx = 13u64;

    w.write_bits(seq_profile, 3);
    w.write_bit(still_picture);
    w.write_bit(reduced_still_picture_header);
    w.write_bit(timing_info_present);
    w.write_bit(initial_display_delay_present);
    w.write_bits(operating_points_cnt_minus_1, 5);
    w.write_bits(operating_point_idc, 12);
    w.write_bits(seq_level_idx, 5);
    w.write_bit(false);

    let frame_width_bits_minus_1 = bits_needed(width - 1) - 1;
    let frame_height_bits_minus_1 = bits_needed(height - 1) - 1;
    w.write_bits(frame_width_bits_minus_1 as u64, 4);
    w.write_bits(frame_height_bits_minus_1 as u64, 4);
    w.write_bits((width - 1) as u64, frame_width_bits_minus_1 + 1);
    w.write_bits((height - 1) as u64, frame_height_bits_minus_1 + 1);

    let frame_id_numbers_present = false;
    let use_128x128_superblock = false;
    let enable_filter_intra = false;
    let enable_intra_edge_filter = false;
    let enable_interintra_compound = false;
    let enable_masked_compound = false;
    let enable_warped_motion = false;
    let enable_dual_filter = false;
    let enable_order_hint = false;

    w.write_bit(frame_id_numbers_present);
    w.write_bit(use_128x128_superblock);
    w.write_bit(enable_filter_intra);
    w.write_bit(enable_intra_edge_filter);
    w.write_bit(enable_interintra_compound);
    w.write_bit(enable_masked_compound);
    w.write_bit(enable_warped_motion);
    w.write_bit(enable_dual_filter);
    w.write_bit(enable_order_hint);

    let seq_choose_screen_content_tools = false;
    let seq_force_screen_content_tools = false;
    w.write_bit(seq_choose_screen_content_tools);
    w.write_bit(seq_force_screen_content_tools);

    let enable_superres = false;
    let enable_cdef = true;
    let enable_restoration = false;
    w.write_bit(enable_superres);
    w.write_bit(enable_cdef);
    w.write_bit(enable_restoration);

    let high_bitdepth = false;
    let mono_chrome = false;
    let color_description_present = false;
    let color_range = false;
    let chroma_sample_position = 0u64;
    let separate_uv_delta_q = false;
    let film_grain_params_present = false;

    w.write_bit(high_bitdepth);
    w.write_bit(mono_chrome);
    w.write_bit(color_description_present);
    w.write_bit(color_range);
    w.write_bits(chroma_sample_position, 2);
    w.write_bit(separate_uv_delta_q);
    w.write_bit(film_grain_params_present);

    w.write_bit(true);

    w.finalize()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::bitwriter::BitWriter;

    #[test]
    fn bits_needed_zero() {
        assert_eq!(bits_needed(0), 1);
    }

    #[test]
    fn bits_needed_one() {
        assert_eq!(bits_needed(1), 1);
    }

    #[test]
    fn bits_needed_63() {
        assert_eq!(bits_needed(63), 6);
    }

    #[test]
    fn bits_needed_99() {
        assert_eq!(bits_needed(99), 7);
    }

    #[test]
    fn bits_needed_1919() {
        assert_eq!(bits_needed(1919), 11);
    }

    #[test]
    fn sequence_header_64x64() {
        let bytes = encode_sequence_header(64, 64);

        let mut expected = BitWriter::new();
        expected.write_bits(0, 3);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bits(0, 5);
        expected.write_bits(0, 12);
        expected.write_bits(13, 5);
        expected.write_bit(false);
        expected.write_bits(5, 4);
        expected.write_bits(5, 4);
        expected.write_bits(63, 6);
        expected.write_bits(63, 6);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bits(0, 2);
        expected.write_bit(false);
        expected.write_bit(true);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bit(false);
        expected.write_bits(0, 2);
        expected.write_bit(false);
        expected.write_bit(false);

        expected.write_bit(true);

        assert_eq!(bytes, expected.finalize());
    }

    #[test]
    fn sequence_header_100x100() {
        let bytes = encode_sequence_header(100, 100);
        assert!(bytes.len() >= 8 && bytes.len() <= 12);
    }

    #[test]
    fn sequence_header_320x240() {
        let bytes = encode_sequence_header(320, 240);
        assert!(bytes.len() >= 8 && bytes.len() <= 12);
    }

    #[test]
    fn sequence_header_1920x1080() {
        let bytes = encode_sequence_header(1920, 1080);
        assert!(bytes.len() >= 8 && bytes.len() <= 12);
    }

    #[test]
    fn sequence_header_1x1() {
        let bytes = encode_sequence_header(1, 1);
        assert!(bytes.len() >= 8 && bytes.len() <= 12);
    }

    #[test]
    fn different_dimensions_produce_different_output() {
        let small = encode_sequence_header(64, 64);
        let large = encode_sequence_header(1920, 1080);
        assert_ne!(small, large);
    }

    #[test]
    fn width_bits_vary_with_dimension() {
        let bytes_64 = encode_sequence_header(64, 64);
        let bytes_1920 = encode_sequence_header(1920, 1080);
        assert!(bytes_1920.len() > bytes_64.len());
    }
}