use byteorder_lite::BigEndian;
use byteorder_lite::{LittleEndian, ReadBytesExt};
use std::cmp;
use std::default::Default;
use std::io::Read;
use std::io::{Cursor, ErrorKind};
use crate::decoder::DecodingError;
use super::loop_filter;
use super::transform;
const MAX_SEGMENTS: usize = 4;
const NUM_DCT_TOKENS: usize = 12;
const DC_PRED: i8 = 0;
const V_PRED: i8 = 1;
const H_PRED: i8 = 2;
const TM_PRED: i8 = 3;
const B_PRED: i8 = 4;
const B_DC_PRED: i8 = 0;
const B_TM_PRED: i8 = 1;
const B_VE_PRED: i8 = 2;
const B_HE_PRED: i8 = 3;
const B_LD_PRED: i8 = 4;
const B_RD_PRED: i8 = 5;
const B_VR_PRED: i8 = 6;
const B_VL_PRED: i8 = 7;
const B_HD_PRED: i8 = 8;
const B_HU_PRED: i8 = 9;
#[repr(i8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
enum LumaMode {
#[default]
DC = DC_PRED,
V = V_PRED,
H = H_PRED,
TM = TM_PRED,
B = B_PRED,
}
#[repr(i8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
enum ChromaMode {
#[default]
DC = DC_PRED,
V = V_PRED,
H = H_PRED,
TM = TM_PRED,
}
#[repr(i8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
enum IntraMode {
#[default]
DC = B_DC_PRED,
TM = B_TM_PRED,
VE = B_VE_PRED,
HE = B_HE_PRED,
LD = B_LD_PRED,
RD = B_RD_PRED,
VR = B_VR_PRED,
VL = B_VL_PRED,
HD = B_HD_PRED,
HU = B_HU_PRED,
}
type Prob = u8;
static SEGMENT_ID_TREE: [i8; 6] = [2, 4, -0, -1, -2, -3];
static KEYFRAME_YMODE_TREE: [i8; 8] = [-B_PRED, 2, 4, 6, -DC_PRED, -V_PRED, -H_PRED, -TM_PRED];
static KEYFRAME_YMODE_PROBS: [Prob; 4] = [145, 156, 163, 128];
static KEYFRAME_BPRED_MODE_TREE: [i8; 18] = [
-B_DC_PRED, 2, -B_TM_PRED, 4, -B_VE_PRED, 6, 8, 12, -B_HE_PRED, 10, -B_RD_PRED, -B_VR_PRED,
-B_LD_PRED, 14, -B_VL_PRED, 16, -B_HD_PRED, -B_HU_PRED,
];
static KEYFRAME_BPRED_MODE_PROBS: [[[u8; 9]; 10]; 10] = [
[
[231, 120, 48, 89, 115, 113, 120, 152, 112],
[152, 179, 64, 126, 170, 118, 46, 70, 95],
[175, 69, 143, 80, 85, 82, 72, 155, 103],
[56, 58, 10, 171, 218, 189, 17, 13, 152],
[144, 71, 10, 38, 171, 213, 144, 34, 26],
[114, 26, 17, 163, 44, 195, 21, 10, 173],
[121, 24, 80, 195, 26, 62, 44, 64, 85],
[170, 46, 55, 19, 136, 160, 33, 206, 71],
[63, 20, 8, 114, 114, 208, 12, 9, 226],
[81, 40, 11, 96, 182, 84, 29, 16, 36],
],
[
[134, 183, 89, 137, 98, 101, 106, 165, 148],
[72, 187, 100, 130, 157, 111, 32, 75, 80],
[66, 102, 167, 99, 74, 62, 40, 234, 128],
[41, 53, 9, 178, 241, 141, 26, 8, 107],
[104, 79, 12, 27, 217, 255, 87, 17, 7],
[74, 43, 26, 146, 73, 166, 49, 23, 157],
[65, 38, 105, 160, 51, 52, 31, 115, 128],
[87, 68, 71, 44, 114, 51, 15, 186, 23],
[47, 41, 14, 110, 182, 183, 21, 17, 194],
[66, 45, 25, 102, 197, 189, 23, 18, 22],
],
[
[88, 88, 147, 150, 42, 46, 45, 196, 205],
[43, 97, 183, 117, 85, 38, 35, 179, 61],
[39, 53, 200, 87, 26, 21, 43, 232, 171],
[56, 34, 51, 104, 114, 102, 29, 93, 77],
[107, 54, 32, 26, 51, 1, 81, 43, 31],
[39, 28, 85, 171, 58, 165, 90, 98, 64],
[34, 22, 116, 206, 23, 34, 43, 166, 73],
[68, 25, 106, 22, 64, 171, 36, 225, 114],
[34, 19, 21, 102, 132, 188, 16, 76, 124],
[62, 18, 78, 95, 85, 57, 50, 48, 51],
],
[
[193, 101, 35, 159, 215, 111, 89, 46, 111],
[60, 148, 31, 172, 219, 228, 21, 18, 111],
[112, 113, 77, 85, 179, 255, 38, 120, 114],
[40, 42, 1, 196, 245, 209, 10, 25, 109],
[100, 80, 8, 43, 154, 1, 51, 26, 71],
[88, 43, 29, 140, 166, 213, 37, 43, 154],
[61, 63, 30, 155, 67, 45, 68, 1, 209],
[142, 78, 78, 16, 255, 128, 34, 197, 171],
[41, 40, 5, 102, 211, 183, 4, 1, 221],
[51, 50, 17, 168, 209, 192, 23, 25, 82],
],
[
[125, 98, 42, 88, 104, 85, 117, 175, 82],
[95, 84, 53, 89, 128, 100, 113, 101, 45],
[75, 79, 123, 47, 51, 128, 81, 171, 1],
[57, 17, 5, 71, 102, 57, 53, 41, 49],
[115, 21, 2, 10, 102, 255, 166, 23, 6],
[38, 33, 13, 121, 57, 73, 26, 1, 85],
[41, 10, 67, 138, 77, 110, 90, 47, 114],
[101, 29, 16, 10, 85, 128, 101, 196, 26],
[57, 18, 10, 102, 102, 213, 34, 20, 43],
[117, 20, 15, 36, 163, 128, 68, 1, 26],
],
[
[138, 31, 36, 171, 27, 166, 38, 44, 229],
[67, 87, 58, 169, 82, 115, 26, 59, 179],
[63, 59, 90, 180, 59, 166, 93, 73, 154],
[40, 40, 21, 116, 143, 209, 34, 39, 175],
[57, 46, 22, 24, 128, 1, 54, 17, 37],
[47, 15, 16, 183, 34, 223, 49, 45, 183],
[46, 17, 33, 183, 6, 98, 15, 32, 183],
[65, 32, 73, 115, 28, 128, 23, 128, 205],
[40, 3, 9, 115, 51, 192, 18, 6, 223],
[87, 37, 9, 115, 59, 77, 64, 21, 47],
],
[
[104, 55, 44, 218, 9, 54, 53, 130, 226],
[64, 90, 70, 205, 40, 41, 23, 26, 57],
[54, 57, 112, 184, 5, 41, 38, 166, 213],
[30, 34, 26, 133, 152, 116, 10, 32, 134],
[75, 32, 12, 51, 192, 255, 160, 43, 51],
[39, 19, 53, 221, 26, 114, 32, 73, 255],
[31, 9, 65, 234, 2, 15, 1, 118, 73],
[88, 31, 35, 67, 102, 85, 55, 186, 85],
[56, 21, 23, 111, 59, 205, 45, 37, 192],
[55, 38, 70, 124, 73, 102, 1, 34, 98],
],
[
[102, 61, 71, 37, 34, 53, 31, 243, 192],
[69, 60, 71, 38, 73, 119, 28, 222, 37],
[68, 45, 128, 34, 1, 47, 11, 245, 171],
[62, 17, 19, 70, 146, 85, 55, 62, 70],
[75, 15, 9, 9, 64, 255, 184, 119, 16],
[37, 43, 37, 154, 100, 163, 85, 160, 1],
[63, 9, 92, 136, 28, 64, 32, 201, 85],
[86, 6, 28, 5, 64, 255, 25, 248, 1],
[56, 8, 17, 132, 137, 255, 55, 116, 128],
[58, 15, 20, 82, 135, 57, 26, 121, 40],
],
[
[164, 50, 31, 137, 154, 133, 25, 35, 218],
[51, 103, 44, 131, 131, 123, 31, 6, 158],
[86, 40, 64, 135, 148, 224, 45, 183, 128],
[22, 26, 17, 131, 240, 154, 14, 1, 209],
[83, 12, 13, 54, 192, 255, 68, 47, 28],
[45, 16, 21, 91, 64, 222, 7, 1, 197],
[56, 21, 39, 155, 60, 138, 23, 102, 213],
[85, 26, 85, 85, 128, 128, 32, 146, 171],
[18, 11, 7, 63, 144, 171, 4, 4, 246],
[35, 27, 10, 146, 174, 171, 12, 26, 128],
],
[
[190, 80, 35, 99, 180, 80, 126, 54, 45],
[85, 126, 47, 87, 176, 51, 41, 20, 32],
[101, 75, 128, 139, 118, 146, 116, 128, 85],
[56, 41, 15, 176, 236, 85, 37, 9, 62],
[146, 36, 19, 30, 171, 255, 97, 27, 20],
[71, 30, 17, 119, 118, 255, 17, 18, 138],
[101, 38, 60, 138, 55, 70, 43, 26, 142],
[138, 45, 61, 62, 219, 1, 81, 188, 64],
[32, 41, 20, 117, 151, 142, 20, 21, 163],
[112, 19, 12, 61, 195, 128, 48, 4, 24],
],
];
static KEYFRAME_UV_MODE_TREE: [i8; 6] = [-DC_PRED, 2, -V_PRED, 4, -H_PRED, -TM_PRED];
static KEYFRAME_UV_MODE_PROBS: [Prob; 3] = [142, 114, 183];
type TokenProbTables = [[[[Prob; NUM_DCT_TOKENS - 1]; 3]; 8]; 4];
static COEFF_UPDATE_PROBS: TokenProbTables = [
[
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255],
[249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255],
[234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255],
[250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255],
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
],
[
[
[217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255],
[234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255],
],
[
[255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255],
[250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
],
[
[
[186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255],
[234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255],
[251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255],
],
[
[255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255],
],
[
[255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
],
[
[
[248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255],
[248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255],
[246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255],
[252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255],
],
[
[255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255],
[248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255],
[253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255],
[252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255],
[250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
[
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
],
],
];
static COEFF_PROBS: TokenProbTables = [
[
[
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
],
[
[253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128],
[189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128],
[106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128],
],
[
[1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128],
[181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128],
[78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128],
],
[
[1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128],
[184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128],
[77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128],
],
[
[1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128],
[170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128],
[37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128],
],
[
[1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128],
[207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128],
[102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128],
],
[
[1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128],
[177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128],
[80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128],
],
[
[1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
[246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
[255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
],
],
[
[
[198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62],
[131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1],
[68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128],
],
[
[1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128],
[184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128],
[81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128],
],
[
[1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128],
[99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128],
[23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128],
],
[
[1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128],
[109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128],
[44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128],
],
[
[1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128],
[94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128],
[22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128],
],
[
[1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128],
[124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128],
[35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128],
],
[
[1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128],
[121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128],
[45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128],
],
[
[1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128],
[203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128],
[137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128],
],
],
[
[
[253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128],
[175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128],
[73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128],
],
[
[1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128],
[239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128],
[155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128],
],
[
[1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128],
[201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128],
[69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128],
],
[
[1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128],
[223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128],
[141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128],
],
[
[1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128],
[190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128],
[149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
],
[
[1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128],
[247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128],
[240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128],
],
[
[1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128],
[213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128],
[55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128],
],
[
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
[128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128],
],
],
[
[
[202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255],
[126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128],
[61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128],
],
[
[1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128],
[166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128],
[39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128],
],
[
[1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128],
[124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128],
[24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128],
],
[
[1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128],
[149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128],
[28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128],
],
[
[1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128],
[123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128],
[20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128],
],
[
[1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128],
[168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128],
[47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128],
],
[
[1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128],
[141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128],
[42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128],
],
[
[1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
[244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
[238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128],
],
],
];
const DCT_0: i8 = 0;
const DCT_1: i8 = 1;
const DCT_2: i8 = 2;
const DCT_3: i8 = 3;
const DCT_4: i8 = 4;
const DCT_CAT1: i8 = 5;
const DCT_CAT2: i8 = 6;
const DCT_CAT3: i8 = 7;
const DCT_CAT4: i8 = 8;
const DCT_CAT5: i8 = 9;
const DCT_CAT6: i8 = 10;
const DCT_EOB: i8 = 11;
static DCT_TOKEN_TREE: [i8; 22] = [
-DCT_EOB, 2, -DCT_0, 4, -DCT_1, 6, 8, 12, -DCT_2, 10, -DCT_3, -DCT_4, 14, 16, -DCT_CAT1,
-DCT_CAT2, 18, 20, -DCT_CAT3, -DCT_CAT4, -DCT_CAT5, -DCT_CAT6,
];
static PROB_DCT_CAT: [[Prob; 12]; 6] = [
[159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[165, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[173, 148, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[176, 155, 140, 135, 0, 0, 0, 0, 0, 0, 0, 0],
[180, 157, 141, 134, 130, 0, 0, 0, 0, 0, 0, 0],
[254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0],
];
static DCT_CAT_BASE: [u8; 6] = [5, 7, 11, 19, 35, 67];
static COEFF_BANDS: [u8; 16] = [0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7];
#[rustfmt::skip]
static DC_QUANT: [i16; 128] = [
4, 5, 6, 7, 8, 9, 10, 10,
11, 12, 13, 14, 15, 16, 17, 17,
18, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 25, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36,
37, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89,
91, 93, 95, 96, 98, 100, 101, 102,
104, 106, 108, 110, 112, 114, 116, 118,
122, 124, 126, 128, 130, 132, 134, 136,
138, 140, 143, 145, 148, 151, 154, 157,
];
#[rustfmt::skip]
static AC_QUANT: [i16; 128] = [
4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 60,
62, 64, 66, 68, 70, 72, 74, 76,
78, 80, 82, 84, 86, 88, 90, 92,
94, 96, 98, 100, 102, 104, 106, 108,
110, 112, 114, 116, 119, 122, 125, 128,
131, 134, 137, 140, 143, 146, 149, 152,
155, 158, 161, 164, 167, 170, 173, 177,
181, 185, 189, 193, 197, 201, 205, 209,
213, 217, 221, 225, 229, 234, 239, 245,
249, 254, 259, 264, 269, 274, 279, 284,
];
static ZIGZAG: [u8; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
struct BoolReader {
reader: Cursor<Vec<u8>>,
range: u32,
value: u32,
bit_count: u8,
eof: bool,
}
impl BoolReader {
pub(crate) fn new() -> BoolReader {
BoolReader {
reader: Default::default(),
range: 0,
value: 0,
bit_count: 0,
eof: false,
}
}
pub(crate) fn init(&mut self, buf: Vec<u8>) -> Result<(), DecodingError> {
if buf.len() < 2 {
return Err(DecodingError::NotEnoughInitData);
}
self.reader = Cursor::new(buf);
self.value = self.reader.read_u16::<BigEndian>()? as u32;
self.range = 255;
self.bit_count = 0;
Ok(())
}
pub(crate) fn read_bool(&mut self, probability: u8) -> Result<bool, DecodingError> {
let split = 1 + (((self.range - 1) * u32::from(probability)) >> 8);
let bigsplit = split << 8;
let retval = if self.value >= bigsplit {
self.range -= split;
self.value -= bigsplit;
true
} else {
self.range = split;
false
};
if self.range < 128 {
let shift = self.range.leading_zeros() - 24;
self.value <<= shift;
self.range <<= shift;
self.bit_count += shift as u8;
if self.bit_count >= 8 {
self.bit_count %= 8;
match self.reader.read_u8() {
Ok(v) => self.value |= u32::from(v) << self.bit_count,
Err(e) if e.kind() == ErrorKind::UnexpectedEof && !self.eof => self.eof = true,
Err(e) => return Err(DecodingError::IoError(e)),
};
}
}
Ok(retval)
}
pub(crate) fn read_literal(&mut self, n: u8) -> Result<u8, DecodingError> {
let mut v = 0u8;
let mut n = n;
while n != 0 {
v = (v << 1) + self.read_bool(128u8)? as u8;
n -= 1;
}
Ok(v)
}
pub(crate) fn read_magnitude_and_sign(&mut self, n: u8) -> Result<i32, DecodingError> {
let magnitude = self.read_literal(n)?;
let sign = self.read_literal(1)?;
if sign == 1 {
Ok(-i32::from(magnitude))
} else {
Ok(i32::from(magnitude))
}
}
pub(crate) fn read_with_tree(
&mut self,
tree: &[i8],
probs: &[Prob],
start: isize,
) -> Result<i8, DecodingError> {
let mut index = start;
loop {
let a = self.read_bool(probs[index as usize >> 1])?;
let b = index + a as isize;
index = tree[b as usize] as isize;
if index <= 0 {
break;
}
}
Ok(-index as i8)
}
pub(crate) fn read_flag(&mut self) -> Result<bool, DecodingError> {
Ok(0 != self.read_literal(1)?)
}
}
#[derive(Default, Clone, Copy)]
struct MacroBlock {
bpred: [IntraMode; 16],
complexity: [u8; 9],
luma_mode: LumaMode,
chroma_mode: ChromaMode,
segmentid: u8,
coeffs_skipped: bool,
}
#[derive(Default, Debug, Clone)]
pub struct Frame {
pub width: u16,
pub height: u16,
pub ybuf: Vec<u8>,
pub ubuf: Vec<u8>,
pub vbuf: Vec<u8>,
pub keyframe: bool,
version: u8,
pub for_display: bool,
pub pixel_type: u8,
filter_type: bool, filter_level: u8,
sharpness_level: u8,
}
impl Frame {
fn chroma_width(&self) -> u16 {
(self.width + 1) / 2
}
fn chroma_height(&self) -> u16 {
(self.height + 1) / 2
}
pub(crate) fn fill_rgb(&self, buf: &mut [u8]) {
const BPP: usize = 3;
let mut index = 0_usize;
for (y, row) in buf
.chunks_exact_mut(usize::from(self.width) * BPP)
.enumerate()
{
let chroma_index = usize::from(self.chroma_width()) * (y / 2);
let next_index = index + usize::from(self.width);
Frame::fill_rgb_row(
&self.ybuf[index..next_index],
&self.ubuf[chroma_index..],
&self.vbuf[chroma_index..],
row,
);
index = next_index;
}
}
fn fill_rgb_row(y_vec: &[u8], u_vec: &[u8], v_vec: &[u8], rgb: &mut [u8]) {
let mut rgb_chunks = rgb.chunks_exact_mut(6);
let mut y_chunks = y_vec.chunks_exact(2);
let mut u_iter = u_vec.iter();
let mut v_iter = v_vec.iter();
for (((rgb, y), &u), &v) in (&mut rgb_chunks)
.zip(&mut y_chunks)
.zip(&mut u_iter)
.zip(&mut v_iter)
{
let coeffs = [
mulhi(v, 26149),
mulhi(u, 6419),
mulhi(v, 13320),
mulhi(u, 33050),
];
rgb[0] = clip(mulhi(y[0], 19077) + coeffs[0] - 14234);
rgb[1] = clip(mulhi(y[0], 19077) - coeffs[1] - coeffs[2] + 8708);
rgb[2] = clip(mulhi(y[0], 19077) + coeffs[3] - 17685);
rgb[3] = clip(mulhi(y[1], 19077) + coeffs[0] - 14234);
rgb[4] = clip(mulhi(y[1], 19077) - coeffs[1] - coeffs[2] + 8708);
rgb[5] = clip(mulhi(y[1], 19077) + coeffs[3] - 17685);
}
let remainder = rgb_chunks.into_remainder();
if remainder.len() >= 3 {
if let (Some(&y), Some(&u), Some(&v)) = (
y_chunks.remainder().iter().next(),
u_iter.next(),
v_iter.next(),
) {
let coeffs = [
mulhi(v, 26149),
mulhi(u, 6419),
mulhi(v, 13320),
mulhi(u, 33050),
];
remainder[0] = clip(mulhi(y, 19077) + coeffs[0] - 14234);
remainder[1] = clip(mulhi(y, 19077) - coeffs[1] - coeffs[2] + 8708);
remainder[2] = clip(mulhi(y, 19077) + coeffs[3] - 17685);
}
}
}
pub(crate) fn fill_rgba(&self, buf: &mut [u8]) {
let mut index = 0_usize;
for (y, row) in buf
.chunks_exact_mut(usize::from(self.width) * 4)
.enumerate()
{
let chroma_index_row = usize::from(self.chroma_width()) * (y / 2);
for (x, rgb_chunk) in row.chunks_exact_mut(4).enumerate() {
let chroma_index = chroma_index_row + x / 2;
Frame::fill_single(
self.ybuf[index],
self.ubuf[chroma_index],
self.vbuf[chroma_index],
rgb_chunk,
);
index += 1;
}
}
}
fn fill_single(y: u8, u: u8, v: u8, rgb: &mut [u8]) {
rgb[0] = clip(mulhi(y, 19077) + mulhi(v, 26149) - 14234);
rgb[1] = clip(mulhi(y, 19077) - mulhi(u, 6419) - mulhi(v, 13320) + 8708);
rgb[2] = clip(mulhi(y, 19077) + mulhi(u, 33050) - 17685);
}
pub fn get_buf_size(&self) -> usize {
self.ybuf.len() * 3
}
}
fn mulhi(v: u8, coeff: u16) -> i32 {
((u32::from(v) * u32::from(coeff)) >> 8) as i32
}
#[allow(clippy::manual_clamp)]
fn clip(v: i32) -> u8 {
const YUV_FIX2: i32 = 6;
(v >> YUV_FIX2).max(0).min(255) as u8
}
#[derive(Clone, Copy, Default)]
struct Segment {
ydc: i16,
yac: i16,
y2dc: i16,
y2ac: i16,
uvdc: i16,
uvac: i16,
delta_values: bool,
quantizer_level: i8,
loopfilter_level: i8,
}
pub struct Vp8Decoder<R> {
r: R,
b: BoolReader,
mbwidth: u16,
mbheight: u16,
macroblocks: Vec<MacroBlock>,
frame: Frame,
segments_enabled: bool,
segments_update_map: bool,
segment: [Segment; MAX_SEGMENTS],
ref_delta: [i32; 4],
mode_delta: [i32; 4],
partitions: [BoolReader; 8],
num_partitions: u8,
segment_tree_probs: [Prob; 3],
token_probs: Box<TokenProbTables>,
prob_intra: Prob,
prob_skip_false: Option<Prob>,
top: Vec<MacroBlock>,
left: MacroBlock,
top_border: Vec<u8>,
left_border: Vec<u8>,
}
impl<R: Read> Vp8Decoder<R> {
pub fn new(r: R) -> Vp8Decoder<R> {
let f = Frame::default();
let s = Segment::default();
let m = MacroBlock::default();
Vp8Decoder {
r,
b: BoolReader::new(),
mbwidth: 0,
mbheight: 0,
macroblocks: Vec::new(),
frame: f,
segments_enabled: false,
segments_update_map: false,
segment: [s; MAX_SEGMENTS],
ref_delta: [0; 4],
mode_delta: [0; 4],
partitions: [
BoolReader::new(),
BoolReader::new(),
BoolReader::new(),
BoolReader::new(),
BoolReader::new(),
BoolReader::new(),
BoolReader::new(),
BoolReader::new(),
],
num_partitions: 1,
segment_tree_probs: [255u8; 3],
token_probs: Box::new(COEFF_PROBS),
prob_intra: 0u8,
prob_skip_false: None,
top: Vec::new(),
left: m,
top_border: Vec::new(),
left_border: Vec::new(),
}
}
fn update_token_probabilities(&mut self) -> Result<(), DecodingError> {
for (i, is) in COEFF_UPDATE_PROBS.iter().enumerate() {
for (j, js) in is.iter().enumerate() {
for (k, ks) in js.iter().enumerate() {
for (t, prob) in ks.iter().enumerate().take(NUM_DCT_TOKENS - 1) {
if self.b.read_bool(*prob)? {
let v = self.b.read_literal(8)?;
self.token_probs[i][j][k][t] = v;
}
}
}
}
}
Ok(())
}
fn init_partitions(&mut self, n: usize) -> Result<(), DecodingError> {
if n > 1 {
let mut sizes = vec![0; 3 * n - 3];
self.r.read_exact(sizes.as_mut_slice())?;
for (i, s) in sizes.chunks(3).enumerate() {
let size = { s }
.read_u24::<LittleEndian>()
.expect("Reading from &[u8] can't fail and the chunk is complete");
let mut buf = vec![0; size as usize];
self.r.read_exact(buf.as_mut_slice())?;
self.partitions[i].init(buf)?;
}
}
let mut buf = Vec::new();
self.r.read_to_end(&mut buf)?;
self.partitions[n - 1].init(buf)?;
Ok(())
}
fn read_quantization_indices(&mut self) -> Result<(), DecodingError> {
fn dc_quant(index: i32) -> i16 {
DC_QUANT[index.clamp(0, 127) as usize]
}
fn ac_quant(index: i32) -> i16 {
AC_QUANT[index.clamp(0, 127) as usize]
}
let yac_abs = self.b.read_literal(7)?;
let ydc_delta = if self.b.read_flag()? {
self.b.read_magnitude_and_sign(4)?
} else {
0
};
let y2dc_delta = if self.b.read_flag()? {
self.b.read_magnitude_and_sign(4)?
} else {
0
};
let y2ac_delta = if self.b.read_flag()? {
self.b.read_magnitude_and_sign(4)?
} else {
0
};
let uvdc_delta = if self.b.read_flag()? {
self.b.read_magnitude_and_sign(4)?
} else {
0
};
let uvac_delta = if self.b.read_flag()? {
self.b.read_magnitude_and_sign(4)?
} else {
0
};
let n = if self.segments_enabled {
MAX_SEGMENTS
} else {
1
};
for i in 0usize..n {
let base = i32::from(if self.segments_enabled {
if !self.segment[i].delta_values {
i16::from(self.segment[i].quantizer_level)
} else {
i16::from(self.segment[i].quantizer_level) + i16::from(yac_abs)
}
} else {
i16::from(yac_abs)
});
self.segment[i].ydc = dc_quant(base + ydc_delta);
self.segment[i].yac = ac_quant(base);
self.segment[i].y2dc = dc_quant(base + y2dc_delta) * 2;
self.segment[i].y2ac = (i32::from(ac_quant(base + y2ac_delta)) * 155 / 100) as i16;
self.segment[i].uvdc = dc_quant(base + uvdc_delta);
self.segment[i].uvac = ac_quant(base + uvac_delta);
if self.segment[i].y2ac < 8 {
self.segment[i].y2ac = 8;
}
if self.segment[i].uvdc > 132 {
self.segment[i].uvdc = 132;
}
}
Ok(())
}
fn read_loop_filter_adjustments(&mut self) -> Result<(), DecodingError> {
if self.b.read_flag()? {
for i in 0usize..4 {
let ref_frame_delta_update_flag = self.b.read_flag()?;
self.ref_delta[i] = if ref_frame_delta_update_flag {
self.b.read_magnitude_and_sign(6)?
} else {
0i32
};
}
for i in 0usize..4 {
let mb_mode_delta_update_flag = self.b.read_flag()?;
self.mode_delta[i] = if mb_mode_delta_update_flag {
self.b.read_magnitude_and_sign(6)?
} else {
0i32
};
}
}
Ok(())
}
fn read_segment_updates(&mut self) -> Result<(), DecodingError> {
self.segments_update_map = self.b.read_flag()?;
let update_segment_feature_data = self.b.read_flag()?;
if update_segment_feature_data {
let segment_feature_mode = self.b.read_flag()?;
for i in 0usize..MAX_SEGMENTS {
self.segment[i].delta_values = !segment_feature_mode;
}
for i in 0usize..MAX_SEGMENTS {
let update = self.b.read_flag()?;
self.segment[i].quantizer_level = if update {
self.b.read_magnitude_and_sign(7)?
} else {
0i32
} as i8;
}
for i in 0usize..MAX_SEGMENTS {
let update = self.b.read_flag()?;
self.segment[i].loopfilter_level = if update {
self.b.read_magnitude_and_sign(6)?
} else {
0i32
} as i8;
}
}
if self.segments_update_map {
for i in 0usize..3 {
let update = self.b.read_flag()?;
self.segment_tree_probs[i] = if update { self.b.read_literal(8)? } else { 255 };
}
}
Ok(())
}
fn read_frame_header(&mut self) -> Result<(), DecodingError> {
let tag = self.r.read_u24::<LittleEndian>()?;
self.frame.keyframe = tag & 1 == 0;
self.frame.version = ((tag >> 1) & 7) as u8;
self.frame.for_display = (tag >> 4) & 1 != 0;
let first_partition_size = tag >> 5;
if self.frame.keyframe {
let mut tag = [0u8; 3];
self.r.read_exact(&mut tag)?;
if tag != [0x9d, 0x01, 0x2a] {
return Err(DecodingError::Vp8MagicInvalid(tag));
}
let w = self.r.read_u16::<LittleEndian>()?;
let h = self.r.read_u16::<LittleEndian>()?;
self.frame.width = w & 0x3FFF;
self.frame.height = h & 0x3FFF;
self.top = init_top_macroblocks(self.frame.width as usize);
self.left = self.top.first().cloned().unwrap_or_default();
self.mbwidth = (self.frame.width + 15) / 16;
self.mbheight = (self.frame.height + 15) / 16;
self.frame.ybuf = vec![0u8; self.frame.width as usize * self.frame.height as usize];
self.frame.ubuf =
vec![0u8; self.frame.chroma_width() as usize * self.frame.chroma_height() as usize];
self.frame.vbuf =
vec![0u8; self.frame.chroma_width() as usize * self.frame.chroma_height() as usize];
self.top_border = vec![127u8; self.frame.width as usize + 4 + 16];
self.left_border = vec![129u8; 1 + 16];
}
let mut buf = vec![0; first_partition_size as usize];
self.r.read_exact(&mut buf)?;
self.b.init(buf)?;
if self.frame.keyframe {
let color_space = self.b.read_literal(1)?;
self.frame.pixel_type = self.b.read_literal(1)?;
if color_space != 0 {
return Err(DecodingError::ColorSpaceInvalid(color_space));
}
}
self.segments_enabled = self.b.read_flag()?;
if self.segments_enabled {
self.read_segment_updates()?;
}
self.frame.filter_type = self.b.read_flag()?;
self.frame.filter_level = self.b.read_literal(6)?;
self.frame.sharpness_level = self.b.read_literal(3)?;
let lf_adjust_enable = self.b.read_flag()?;
if lf_adjust_enable {
self.read_loop_filter_adjustments()?;
}
self.num_partitions = (1usize << self.b.read_literal(2)? as usize) as u8;
let num_partitions = self.num_partitions as usize;
self.init_partitions(num_partitions)?;
self.read_quantization_indices()?;
if !self.frame.keyframe {
return Err(DecodingError::UnsupportedFeature(
"Non-keyframe frames".to_owned(),
));
} else {
let _ = self.b.read_literal(1);
}
self.update_token_probabilities()?;
let mb_no_skip_coeff = self.b.read_literal(1)?;
self.prob_skip_false = if mb_no_skip_coeff == 1 {
Some(self.b.read_literal(8)?)
} else {
None
};
if !self.frame.keyframe {
self.prob_intra = 0;
return Err(DecodingError::UnsupportedFeature(
"Non-keyframe frames".to_owned(),
));
} else {
}
Ok(())
}
fn read_macroblock_header(&mut self, mbx: usize) -> Result<MacroBlock, DecodingError> {
let mut mb = MacroBlock::default();
if self.segments_enabled && self.segments_update_map {
mb.segmentid = self
.b
.read_with_tree(&SEGMENT_ID_TREE, &self.segment_tree_probs, 0)?
as u8;
};
mb.coeffs_skipped = if self.prob_skip_false.is_some() {
self.b.read_bool(*self.prob_skip_false.as_ref().unwrap())?
} else {
false
};
let inter_predicted = if !self.frame.keyframe {
self.b.read_bool(self.prob_intra)?
} else {
false
};
if inter_predicted {
return Err(DecodingError::UnsupportedFeature(
"VP8 inter-prediction".to_owned(),
));
}
if self.frame.keyframe {
let luma = self
.b
.read_with_tree(&KEYFRAME_YMODE_TREE, &KEYFRAME_YMODE_PROBS, 0)?;
mb.luma_mode =
LumaMode::from_i8(luma).ok_or(DecodingError::LumaPredictionModeInvalid(luma))?;
match mb.luma_mode.into_intra() {
None => {
for y in 0usize..4 {
for x in 0usize..4 {
let top = self.top[mbx].bpred[12 + x];
let left = self.left.bpred[y];
let intra = self.b.read_with_tree(
&KEYFRAME_BPRED_MODE_TREE,
&KEYFRAME_BPRED_MODE_PROBS[top as usize][left as usize],
0,
)?;
let bmode = IntraMode::from_i8(intra)
.ok_or(DecodingError::IntraPredictionModeInvalid(intra))?;
mb.bpred[x + y * 4] = bmode;
self.top[mbx].bpred[12 + x] = bmode;
self.left.bpred[y] = bmode;
}
}
}
Some(mode) => {
for i in 0usize..4 {
mb.bpred[12 + i] = mode;
self.left.bpred[i] = mode;
}
}
}
let chroma =
self.b
.read_with_tree(&KEYFRAME_UV_MODE_TREE, &KEYFRAME_UV_MODE_PROBS, 0)?;
mb.chroma_mode = ChromaMode::from_i8(chroma)
.ok_or(DecodingError::ChromaPredictionModeInvalid(chroma))?;
}
self.top[mbx].chroma_mode = mb.chroma_mode;
self.top[mbx].luma_mode = mb.luma_mode;
self.top[mbx].bpred = mb.bpred;
Ok(mb)
}
fn intra_predict_luma(&mut self, mbx: usize, mby: usize, mb: &MacroBlock, resdata: &[i32]) {
let stride = 1usize + 16 + 4;
let w = self.frame.width as usize;
let mw = self.mbwidth as usize;
let mut ws = create_border_luma(mbx, mby, mw, &self.top_border, &self.left_border);
match mb.luma_mode {
LumaMode::V => predict_vpred(&mut ws, 16, 1, 1, stride),
LumaMode::H => predict_hpred(&mut ws, 16, 1, 1, stride),
LumaMode::TM => predict_tmpred(&mut ws, 16, 1, 1, stride),
LumaMode::DC => predict_dcpred(&mut ws, 16, stride, mby != 0, mbx != 0),
LumaMode::B => predict_4x4(&mut ws, stride, &mb.bpred, resdata),
}
if mb.luma_mode != LumaMode::B {
for y in 0usize..4 {
for x in 0usize..4 {
let i = x + y * 4;
let rb: &[i32; 16] = resdata[i * 16..][..16].try_into().unwrap();
let y0 = 1 + y * 4;
let x0 = 1 + x * 4;
add_residue(&mut ws, rb, y0, x0, stride);
}
}
}
self.left_border[0] = ws[16];
for (i, left) in self.left_border[1..][..16].iter_mut().enumerate() {
*left = ws[(i + 1) * stride + 16];
}
for (top, &w) in self.top_border[mbx * 16..][..16]
.iter_mut()
.zip(&ws[16 * stride + 1..][..16])
{
*top = w;
}
let ylength = cmp::min(self.frame.height as usize - mby * 16, 16);
let xlength = cmp::min(self.frame.width as usize - mbx * 16, 16);
for y in 0usize..ylength {
for (ybuf, &ws) in self.frame.ybuf[(mby * 16 + y) * w + mbx * 16..][..xlength]
.iter_mut()
.zip(ws[(1 + y) * stride + 1..][..xlength].iter())
{
*ybuf = ws;
}
}
}
fn intra_predict_chroma(&mut self, mbx: usize, mby: usize, mb: &MacroBlock, resdata: &[i32]) {
let stride = 1usize + 8;
let w = self.frame.chroma_width() as usize;
let mut uws = [0u8; (8 + 1) * (8 + 1)];
let mut vws = [0u8; (8 + 1) * (8 + 1)];
let ylength = cmp::min(self.frame.chroma_height() as usize - mby * 8, 8);
let xlength = cmp::min(self.frame.chroma_width() as usize - mbx * 8, 8);
for y in 0usize..8 {
let (uy, vy) = if mbx == 0 || y >= ylength {
(129, 129)
} else {
let index = (mby * 8 + y) * w + ((mbx - 1) * 8 + 7);
(self.frame.ubuf[index], self.frame.vbuf[index])
};
uws[(y + 1) * stride] = uy;
vws[(y + 1) * stride] = vy;
}
for x in 0usize..8 {
let (ux, vx) = if mby == 0 || x >= xlength {
(127, 127)
} else {
let index = ((mby - 1) * 8 + 7) * w + (mbx * 8 + x);
(self.frame.ubuf[index], self.frame.vbuf[index])
};
uws[x + 1] = ux;
vws[x + 1] = vx;
}
let (u1, v1) = if mby == 0 {
(127, 127)
} else if mbx == 0 {
(129, 129)
} else {
let index = ((mby - 1) * 8 + 7) * w + (mbx - 1) * 8 + 7;
if index >= self.frame.ubuf.len() {
(127, 127)
} else {
(self.frame.ubuf[index], self.frame.vbuf[index])
}
};
uws[0] = u1;
vws[0] = v1;
match mb.chroma_mode {
ChromaMode::DC => {
predict_dcpred(&mut uws, 8, stride, mby != 0, mbx != 0);
predict_dcpred(&mut vws, 8, stride, mby != 0, mbx != 0);
}
ChromaMode::V => {
predict_vpred(&mut uws, 8, 1, 1, stride);
predict_vpred(&mut vws, 8, 1, 1, stride);
}
ChromaMode::H => {
predict_hpred(&mut uws, 8, 1, 1, stride);
predict_hpred(&mut vws, 8, 1, 1, stride);
}
ChromaMode::TM => {
predict_tmpred(&mut uws, 8, 1, 1, stride);
predict_tmpred(&mut vws, 8, 1, 1, stride);
}
}
for y in 0usize..2 {
for x in 0usize..2 {
let i = x + y * 2;
let urb: &[i32; 16] = resdata[16 * 16 + i * 16..][..16].try_into().unwrap();
let y0 = 1 + y * 4;
let x0 = 1 + x * 4;
add_residue(&mut uws, urb, y0, x0, stride);
let vrb: &[i32; 16] = resdata[20 * 16 + i * 16..][..16].try_into().unwrap();
add_residue(&mut vws, vrb, y0, x0, stride);
}
}
for y in 0usize..ylength {
let uv_buf_index = (mby * 8 + y) * w + mbx * 8;
let ws_index = (1 + y) * stride + 1;
for (((ub, vb), &uw), &vw) in self.frame.ubuf[uv_buf_index..][..xlength]
.iter_mut()
.zip(self.frame.vbuf[uv_buf_index..][..xlength].iter_mut())
.zip(uws[ws_index..][..xlength].iter())
.zip(vws[ws_index..][..xlength].iter())
{
*ub = uw;
*vb = vw;
}
}
}
fn read_coefficients(
&mut self,
block: &mut [i32],
p: usize,
plane: usize,
complexity: usize,
dcq: i16,
acq: i16,
) -> Result<bool, DecodingError> {
let first = if plane == 0 { 1usize } else { 0usize };
let probs = &self.token_probs[plane];
let tree = &DCT_TOKEN_TREE;
let mut complexity = complexity;
let mut has_coefficients = false;
let mut skip = false;
for i in first..16usize {
let table = &probs[COEFF_BANDS[i] as usize][complexity];
let token = if !skip {
self.partitions[p].read_with_tree(tree, table, 0)?
} else {
self.partitions[p].read_with_tree(tree, table, 2)?
};
let mut abs_value = i32::from(match token {
DCT_EOB => break,
DCT_0 => {
skip = true;
has_coefficients = true;
complexity = 0;
continue;
}
literal @ DCT_1..=DCT_4 => i16::from(literal),
category @ DCT_CAT1..=DCT_CAT6 => {
let t = PROB_DCT_CAT[(category - DCT_CAT1) as usize];
let mut extra = 0i16;
let mut j = 0;
while t[j] > 0 {
extra = extra + extra + self.partitions[p].read_bool(t[j])? as i16;
j += 1;
}
i16::from(DCT_CAT_BASE[(category - DCT_CAT1) as usize]) + extra
}
c => panic!("unknown token: {}", c),
});
skip = false;
complexity = if abs_value == 0 {
0
} else if abs_value == 1 {
1
} else {
2
};
if self.partitions[p].read_bool(128)? {
abs_value = -abs_value;
}
block[ZIGZAG[i] as usize] =
abs_value * i32::from(if ZIGZAG[i] > 0 { acq } else { dcq });
has_coefficients = true;
}
Ok(has_coefficients)
}
fn read_residual_data(
&mut self,
mb: &MacroBlock,
mbx: usize,
p: usize,
) -> Result<[i32; 384], DecodingError> {
let sindex = mb.segmentid as usize;
let mut blocks = [0i32; 384];
let mut plane = if mb.luma_mode == LumaMode::B { 3 } else { 1 };
if plane == 1 {
let complexity = self.top[mbx].complexity[0] + self.left.complexity[0];
let mut block = [0i32; 16];
let dcq = self.segment[sindex].y2dc;
let acq = self.segment[sindex].y2ac;
let n = self.read_coefficients(&mut block, p, plane, complexity as usize, dcq, acq)?;
self.left.complexity[0] = if n { 1 } else { 0 };
self.top[mbx].complexity[0] = if n { 1 } else { 0 };
transform::iwht4x4(&mut block);
for k in 0usize..16 {
blocks[16 * k] = block[k];
}
plane = 0;
}
for y in 0usize..4 {
let mut left = self.left.complexity[y + 1];
for x in 0usize..4 {
let i = x + y * 4;
let block = &mut blocks[i * 16..i * 16 + 16];
let complexity = self.top[mbx].complexity[x + 1] + left;
let dcq = self.segment[sindex].ydc;
let acq = self.segment[sindex].yac;
let n = self.read_coefficients(block, p, plane, complexity as usize, dcq, acq)?;
if block[0] != 0 || n {
transform::idct4x4(block);
}
left = if n { 1 } else { 0 };
self.top[mbx].complexity[x + 1] = if n { 1 } else { 0 };
}
self.left.complexity[y + 1] = left;
}
plane = 2;
for &j in &[5usize, 7usize] {
for y in 0usize..2 {
let mut left = self.left.complexity[y + j];
for x in 0usize..2 {
let i = x + y * 2 + if j == 5 { 16 } else { 20 };
let block = &mut blocks[i * 16..i * 16 + 16];
let complexity = self.top[mbx].complexity[x + j] + left;
let dcq = self.segment[sindex].uvdc;
let acq = self.segment[sindex].uvac;
let n =
self.read_coefficients(block, p, plane, complexity as usize, dcq, acq)?;
if block[0] != 0 || n {
transform::idct4x4(block);
}
left = if n { 1 } else { 0 };
self.top[mbx].complexity[x + j] = if n { 1 } else { 0 };
}
self.left.complexity[y + j] = left;
}
}
Ok(blocks)
}
fn loop_filter(&mut self, mbx: usize, mby: usize, mb: &MacroBlock) {
let luma_w = self.frame.width as usize;
let luma_h = self.frame.height as usize;
let chroma_w = self.frame.chroma_width() as usize;
let chroma_h = self.frame.chroma_height() as usize;
let (filter_level, interior_limit, hev_threshold) = self.calculate_filter_parameters(mb);
if filter_level > 0 {
let mbedge_limit = (filter_level + 2) * 2 + interior_limit;
let sub_bedge_limit = (filter_level * 2) + interior_limit;
let luma_ylength = cmp::min(luma_h - 16 * mby, 16);
let luma_xlength = cmp::min(luma_w - 16 * mbx, 16);
let chroma_ylength = cmp::min(chroma_h - 8 * mby, 8);
let chroma_xlength = cmp::min(chroma_w - 8 * mbx, 8);
if mbx > 0 {
if self.frame.filter_type {
if luma_xlength >= 2 {
for y in 0usize..luma_ylength {
let y0 = mby * 16 + y;
let x0 = mbx * 16;
loop_filter::simple_segment(
mbedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
1,
);
}
}
} else {
if luma_xlength >= 4 {
for y in 0usize..luma_ylength {
let y0 = mby * 16 + y;
let x0 = mbx * 16;
loop_filter::macroblock_filter(
hev_threshold,
interior_limit,
mbedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
1,
);
}
}
if chroma_xlength >= 4 {
for y in 0usize..chroma_ylength {
let y0 = mby * 8 + y;
let x0 = mbx * 8;
loop_filter::macroblock_filter(
hev_threshold,
interior_limit,
mbedge_limit,
&mut self.frame.ubuf[..],
y0 * chroma_w + x0,
1,
);
loop_filter::macroblock_filter(
hev_threshold,
interior_limit,
mbedge_limit,
&mut self.frame.vbuf[..],
y0 * chroma_w + x0,
1,
);
}
}
}
}
if mb.luma_mode == LumaMode::B || !mb.coeffs_skipped {
if self.frame.filter_type {
for x in (4usize..luma_xlength - 1).step_by(4) {
for y in 0..luma_ylength {
let y0 = mby * 16 + y;
let x0 = mbx * 16 + x;
loop_filter::simple_segment(
sub_bedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
1,
);
}
}
} else {
if luma_xlength > 3 {
for x in (4usize..luma_xlength - 3).step_by(4) {
for y in 0..luma_ylength {
let y0 = mby * 16 + y;
let x0 = mbx * 16 + x;
loop_filter::subblock_filter(
hev_threshold,
interior_limit,
sub_bedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
1,
);
}
}
}
if chroma_xlength == 8 {
for y in 0usize..chroma_ylength {
let y0 = mby * 8 + y;
let x0 = mbx * 8 + 4;
loop_filter::subblock_filter(
hev_threshold,
interior_limit,
sub_bedge_limit,
&mut self.frame.ubuf[..],
y0 * chroma_w + x0,
1,
);
loop_filter::subblock_filter(
hev_threshold,
interior_limit,
sub_bedge_limit,
&mut self.frame.vbuf[..],
y0 * chroma_w + x0,
1,
);
}
}
}
}
if mby > 0 {
if self.frame.filter_type {
if luma_ylength >= 2 {
for x in 0usize..luma_xlength {
let y0 = mby * 16;
let x0 = mbx * 16 + x;
loop_filter::simple_segment(
mbedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
luma_w,
);
}
}
} else {
if luma_ylength >= 4 {
for x in 0usize..luma_xlength {
let y0 = mby * 16;
let x0 = mbx * 16 + x;
loop_filter::macroblock_filter(
hev_threshold,
interior_limit,
mbedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
luma_w,
);
}
}
if chroma_ylength >= 4 {
for x in 0usize..chroma_xlength {
let y0 = mby * 8;
let x0 = mbx * 8 + x;
loop_filter::macroblock_filter(
hev_threshold,
interior_limit,
mbedge_limit,
&mut self.frame.ubuf[..],
y0 * chroma_w + x0,
chroma_w,
);
loop_filter::macroblock_filter(
hev_threshold,
interior_limit,
mbedge_limit,
&mut self.frame.vbuf[..],
y0 * chroma_w + x0,
chroma_w,
);
}
}
}
}
if mb.luma_mode == LumaMode::B || !mb.coeffs_skipped {
if self.frame.filter_type {
for y in (4usize..luma_ylength - 1).step_by(4) {
for x in 0..luma_xlength {
let y0 = mby * 16 + y;
let x0 = mbx * 16 + x;
loop_filter::simple_segment(
sub_bedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
luma_w,
);
}
}
} else {
if luma_ylength > 3 {
for y in (4usize..luma_ylength - 3).step_by(4) {
for x in 0..luma_xlength {
let y0 = mby * 16 + y;
let x0 = mbx * 16 + x;
loop_filter::subblock_filter(
hev_threshold,
interior_limit,
sub_bedge_limit,
&mut self.frame.ybuf[..],
y0 * luma_w + x0,
luma_w,
);
}
}
}
if chroma_ylength == 8 {
for x in 0..chroma_xlength {
let y0 = mby * 8 + 4;
let x0 = mbx * 8 + x;
loop_filter::subblock_filter(
hev_threshold,
interior_limit,
sub_bedge_limit,
&mut self.frame.ubuf[..],
y0 * chroma_w + x0,
chroma_w,
);
loop_filter::subblock_filter(
hev_threshold,
interior_limit,
sub_bedge_limit,
&mut self.frame.vbuf[..],
y0 * chroma_w + x0,
chroma_w,
);
}
}
}
}
}
}
fn calculate_filter_parameters(&self, macroblock: &MacroBlock) -> (u8, u8, u8) {
let segment = self.segment[macroblock.segmentid as usize];
let mut filter_level = self.frame.filter_level as i32;
if self.segments_enabled {
if segment.delta_values {
filter_level += i32::from(segment.loopfilter_level);
} else {
filter_level = i32::from(segment.loopfilter_level);
}
}
filter_level = filter_level.clamp(0, 63);
if macroblock.luma_mode == LumaMode::B {
filter_level += self.mode_delta[0];
}
let filter_level = filter_level.clamp(0, 63) as u8;
let mut interior_limit = filter_level;
if self.frame.sharpness_level > 0 {
interior_limit >>= if self.frame.sharpness_level > 4 { 2 } else { 1 };
if interior_limit > 9 - self.frame.sharpness_level {
interior_limit = 9 - self.frame.sharpness_level;
}
}
if interior_limit == 0 {
interior_limit = 1;
}
let mut hev_threshold = 0;
#[allow(clippy::collapsible_else_if)]
if self.frame.keyframe {
if filter_level >= 40 {
hev_threshold = 2;
} else {
hev_threshold = 1;
}
} else {
if filter_level >= 40 {
hev_threshold = 3;
} else if filter_level >= 20 {
hev_threshold = 2;
} else if filter_level >= 15 {
hev_threshold = 1;
}
}
(filter_level, interior_limit, hev_threshold)
}
pub fn decode_frame(&mut self) -> Result<&Frame, DecodingError> {
self.read_frame_header()?;
for mby in 0..self.mbheight as usize {
let p = mby % self.num_partitions as usize;
self.left = MacroBlock::default();
for mbx in 0..self.mbwidth as usize {
let mb = self.read_macroblock_header(mbx)?;
let blocks = if !mb.coeffs_skipped {
self.read_residual_data(&mb, mbx, p)?
} else {
if mb.luma_mode != LumaMode::B {
self.left.complexity[0] = 0;
self.top[mbx].complexity[0] = 0;
}
for i in 1usize..9 {
self.left.complexity[i] = 0;
self.top[mbx].complexity[i] = 0;
}
[0i32; 384]
};
self.intra_predict_luma(mbx, mby, &mb, &blocks);
self.intra_predict_chroma(mbx, mby, &mb, &blocks);
self.macroblocks.push(mb);
}
self.left_border = vec![129u8; 1 + 16];
}
for mby in 0..self.mbheight as usize {
for mbx in 0..self.mbwidth as usize {
let mb = self.macroblocks[mby * self.mbwidth as usize + mbx];
self.loop_filter(mbx, mby, &mb);
}
}
Ok(&self.frame)
}
}
impl LumaMode {
fn from_i8(val: i8) -> Option<Self> {
Some(match val {
DC_PRED => LumaMode::DC,
V_PRED => LumaMode::V,
H_PRED => LumaMode::H,
TM_PRED => LumaMode::TM,
B_PRED => LumaMode::B,
_ => return None,
})
}
fn into_intra(self) -> Option<IntraMode> {
Some(match self {
LumaMode::DC => IntraMode::DC,
LumaMode::V => IntraMode::VE,
LumaMode::H => IntraMode::HE,
LumaMode::TM => IntraMode::TM,
LumaMode::B => return None,
})
}
}
impl ChromaMode {
fn from_i8(val: i8) -> Option<Self> {
Some(match val {
DC_PRED => ChromaMode::DC,
V_PRED => ChromaMode::V,
H_PRED => ChromaMode::H,
TM_PRED => ChromaMode::TM,
_ => return None,
})
}
}
impl IntraMode {
fn from_i8(val: i8) -> Option<Self> {
Some(match val {
B_DC_PRED => IntraMode::DC,
B_TM_PRED => IntraMode::TM,
B_VE_PRED => IntraMode::VE,
B_HE_PRED => IntraMode::HE,
B_LD_PRED => IntraMode::LD,
B_RD_PRED => IntraMode::RD,
B_VR_PRED => IntraMode::VR,
B_VL_PRED => IntraMode::VL,
B_HD_PRED => IntraMode::HD,
B_HU_PRED => IntraMode::HU,
_ => return None,
})
}
}
fn init_top_macroblocks(width: usize) -> Vec<MacroBlock> {
let mb_width = (width + 15) / 16;
let mb = MacroBlock {
bpred: [IntraMode::DC; 16],
luma_mode: LumaMode::DC,
..MacroBlock::default()
};
vec![mb; mb_width]
}
fn create_border_luma(mbx: usize, mby: usize, mbw: usize, top: &[u8], left: &[u8]) -> [u8; 357] {
let stride = 1usize + 16 + 4;
let mut ws = [0u8; (1 + 16) * (1 + 16 + 4)];
{
let above = &mut ws[1..stride];
if mby == 0 {
for above in above.iter_mut() {
*above = 127;
}
} else {
for (above, &top) in above[..16].iter_mut().zip(&top[mbx * 16..]) {
*above = top;
}
if mbx == mbw - 1 {
for above in above[16..].iter_mut() {
*above = top[mbx * 16 + 15];
}
} else {
for (above, &top) in above[16..].iter_mut().zip(&top[mbx * 16 + 16..]) {
*above = top;
}
}
}
}
for i in 17usize..stride {
ws[4 * stride + i] = ws[i];
ws[8 * stride + i] = ws[i];
ws[12 * stride + i] = ws[i];
}
if mbx == 0 {
for i in 0usize..16 {
ws[(i + 1) * stride] = 129;
}
} else {
for (i, &left) in (0usize..16).zip(&left[1..]) {
ws[(i + 1) * stride] = left;
}
}
ws[0] = if mby == 0 {
127
} else if mbx == 0 {
129
} else {
left[0]
};
ws
}
fn avg3(left: u8, this: u8, right: u8) -> u8 {
let avg = (u16::from(left) + 2 * u16::from(this) + u16::from(right) + 2) >> 2;
avg as u8
}
fn avg2(this: u8, right: u8) -> u8 {
let avg = (u16::from(this) + u16::from(right) + 1) >> 1;
avg as u8
}
#[allow(clippy::manual_clamp)]
fn add_residue(pblock: &mut [u8], rblock: &[i32; 16], y0: usize, x0: usize, stride: usize) {
let mut pos = y0 * stride + x0;
for row in rblock.chunks(4) {
for (p, &a) in pblock[pos..][..4].iter_mut().zip(row.iter()) {
*p = (a + i32::from(*p)).max(0).min(255) as u8;
}
pos += stride;
}
}
fn predict_4x4(ws: &mut [u8], stride: usize, modes: &[IntraMode], resdata: &[i32]) {
for sby in 0usize..4 {
for sbx in 0usize..4 {
let i = sbx + sby * 4;
let y0 = sby * 4 + 1;
let x0 = sbx * 4 + 1;
match modes[i] {
IntraMode::TM => predict_tmpred(ws, 4, x0, y0, stride),
IntraMode::VE => predict_bvepred(ws, x0, y0, stride),
IntraMode::HE => predict_bhepred(ws, x0, y0, stride),
IntraMode::DC => predict_bdcpred(ws, x0, y0, stride),
IntraMode::LD => predict_bldpred(ws, x0, y0, stride),
IntraMode::RD => predict_brdpred(ws, x0, y0, stride),
IntraMode::VR => predict_bvrpred(ws, x0, y0, stride),
IntraMode::VL => predict_bvlpred(ws, x0, y0, stride),
IntraMode::HD => predict_bhdpred(ws, x0, y0, stride),
IntraMode::HU => predict_bhupred(ws, x0, y0, stride),
}
let rb: &[i32; 16] = resdata[i * 16..][..16].try_into().unwrap();
add_residue(ws, rb, y0, x0, stride);
}
}
}
fn predict_vpred(a: &mut [u8], size: usize, x0: usize, y0: usize, stride: usize) {
let (above, curr) = a.split_at_mut(stride * y0);
let above_slice = &above[x0..];
for curr_chunk in curr.chunks_exact_mut(stride).take(size) {
for (curr, &above) in curr_chunk[1..].iter_mut().zip(above_slice) {
*curr = above;
}
}
}
fn predict_hpred(a: &mut [u8], size: usize, x0: usize, y0: usize, stride: usize) {
for chunk in a.chunks_exact_mut(stride).skip(y0).take(size) {
let left = chunk[x0 - 1];
chunk[x0..].iter_mut().for_each(|a| *a = left);
}
}
fn predict_dcpred(a: &mut [u8], size: usize, stride: usize, above: bool, left: bool) {
let mut sum = 0;
let mut shf = if size == 8 { 2 } else { 3 };
if left {
for y in 0usize..size {
sum += u32::from(a[(y + 1) * stride]);
}
shf += 1;
}
if above {
sum += a[1..=size].iter().fold(0, |acc, &x| acc + u32::from(x));
shf += 1;
}
let dcval = if !left && !above {
128
} else {
(sum + (1 << (shf - 1))) >> shf
};
for y in 0usize..size {
a[1 + stride * (y + 1)..][..size]
.iter_mut()
.for_each(|a| *a = dcval as u8);
}
}
#[allow(clippy::manual_clamp)]
fn predict_tmpred(a: &mut [u8], size: usize, x0: usize, y0: usize, stride: usize) {
let (above, x_block) = a.split_at_mut(y0 * stride + (x0 - 1));
let p = i32::from(above[(y0 - 1) * stride + x0 - 1]);
let above_slice = &above[(y0 - 1) * stride + x0..];
for y in 0usize..size {
let left_minus_p = i32::from(x_block[y * stride]) - p;
x_block[y * stride + 1..][..size]
.iter_mut()
.zip(above_slice)
.for_each(|(cur, &abv)| *cur = (left_minus_p + i32::from(abv)).max(0).min(255) as u8);
}
}
fn predict_bdcpred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let mut v = 4;
a[(y0 - 1) * stride + x0..][..4]
.iter()
.for_each(|&a| v += u32::from(a));
for i in 0usize..4 {
v += u32::from(a[(y0 + i) * stride + x0 - 1]);
}
v >>= 3;
for chunk in a.chunks_exact_mut(stride).skip(y0).take(4) {
for ch in chunk[x0..][..4].iter_mut() {
*ch = v as u8;
}
}
}
fn topleft_pixel(a: &[u8], x0: usize, y0: usize, stride: usize) -> u8 {
a[(y0 - 1) * stride + x0 - 1]
}
fn top_pixels(a: &[u8], x0: usize, y0: usize, stride: usize) -> (u8, u8, u8, u8, u8, u8, u8, u8) {
let pos = (y0 - 1) * stride + x0;
let a_slice = &a[pos..pos + 8];
let a0 = a_slice[0];
let a1 = a_slice[1];
let a2 = a_slice[2];
let a3 = a_slice[3];
let a4 = a_slice[4];
let a5 = a_slice[5];
let a6 = a_slice[6];
let a7 = a_slice[7];
(a0, a1, a2, a3, a4, a5, a6, a7)
}
fn left_pixels(a: &[u8], x0: usize, y0: usize, stride: usize) -> (u8, u8, u8, u8) {
let l0 = a[y0 * stride + x0 - 1];
let l1 = a[(y0 + 1) * stride + x0 - 1];
let l2 = a[(y0 + 2) * stride + x0 - 1];
let l3 = a[(y0 + 3) * stride + x0 - 1];
(l0, l1, l2, l3)
}
fn edge_pixels(
a: &[u8],
x0: usize,
y0: usize,
stride: usize,
) -> (u8, u8, u8, u8, u8, u8, u8, u8, u8) {
let pos = (y0 - 1) * stride + x0 - 1;
let a_slice = &a[pos..=pos + 4];
let e0 = a[pos + 4 * stride];
let e1 = a[pos + 3 * stride];
let e2 = a[pos + 2 * stride];
let e3 = a[pos + stride];
let e4 = a_slice[0];
let e5 = a_slice[1];
let e6 = a_slice[2];
let e7 = a_slice[3];
let e8 = a_slice[4];
(e0, e1, e2, e3, e4, e5, e6, e7, e8)
}
fn predict_bvepred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let p = topleft_pixel(a, x0, y0, stride);
let (a0, a1, a2, a3, a4, _, _, _) = top_pixels(a, x0, y0, stride);
let avg_1 = avg3(p, a0, a1);
let avg_2 = avg3(a0, a1, a2);
let avg_3 = avg3(a1, a2, a3);
let avg_4 = avg3(a2, a3, a4);
let avg = [avg_1, avg_2, avg_3, avg_4];
let mut pos = y0 * stride + x0;
for _ in 0..4 {
a[pos..=pos + 3].copy_from_slice(&avg);
pos += stride;
}
}
fn predict_bhepred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let p = topleft_pixel(a, x0, y0, stride);
let (l0, l1, l2, l3) = left_pixels(a, x0, y0, stride);
let avgs = [
avg3(p, l0, l1),
avg3(l0, l1, l2),
avg3(l1, l2, l3),
avg3(l2, l3, l3),
];
let mut pos = y0 * stride + x0;
for &avg in avgs.iter() {
for a_p in a[pos..=pos + 3].iter_mut() {
*a_p = avg;
}
pos += stride;
}
}
fn predict_bldpred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let (a0, a1, a2, a3, a4, a5, a6, a7) = top_pixels(a, x0, y0, stride);
let avgs = [
avg3(a0, a1, a2),
avg3(a1, a2, a3),
avg3(a2, a3, a4),
avg3(a3, a4, a5),
avg3(a4, a5, a6),
avg3(a5, a6, a7),
avg3(a6, a7, a7),
];
let mut pos = y0 * stride + x0;
for i in 0..4 {
a[pos..=pos + 3].copy_from_slice(&avgs[i..=i + 3]);
pos += stride;
}
}
fn predict_brdpred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let (e0, e1, e2, e3, e4, e5, e6, e7, e8) = edge_pixels(a, x0, y0, stride);
let avgs = [
avg3(e0, e1, e2),
avg3(e1, e2, e3),
avg3(e2, e3, e4),
avg3(e3, e4, e5),
avg3(e4, e5, e6),
avg3(e5, e6, e7),
avg3(e6, e7, e8),
];
let mut pos = y0 * stride + x0;
for i in 0..4 {
a[pos..=pos + 3].copy_from_slice(&avgs[3 - i..7 - i]);
pos += stride;
}
}
fn predict_bvrpred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let (_, e1, e2, e3, e4, e5, e6, e7, e8) = edge_pixels(a, x0, y0, stride);
a[(y0 + 3) * stride + x0] = avg3(e1, e2, e3);
a[(y0 + 2) * stride + x0] = avg3(e2, e3, e4);
a[(y0 + 3) * stride + x0 + 1] = avg3(e3, e4, e5);
a[(y0 + 1) * stride + x0] = avg3(e3, e4, e5);
a[(y0 + 2) * stride + x0 + 1] = avg2(e4, e5);
a[y0 * stride + x0] = avg2(e4, e5);
a[(y0 + 3) * stride + x0 + 2] = avg3(e4, e5, e6);
a[(y0 + 1) * stride + x0 + 1] = avg3(e4, e5, e6);
a[(y0 + 2) * stride + x0 + 2] = avg2(e5, e6);
a[y0 * stride + x0 + 1] = avg2(e5, e6);
a[(y0 + 3) * stride + x0 + 3] = avg3(e5, e6, e7);
a[(y0 + 1) * stride + x0 + 2] = avg3(e5, e6, e7);
a[(y0 + 2) * stride + x0 + 3] = avg2(e6, e7);
a[y0 * stride + x0 + 2] = avg2(e6, e7);
a[(y0 + 1) * stride + x0 + 3] = avg3(e6, e7, e8);
a[y0 * stride + x0 + 3] = avg2(e7, e8);
}
fn predict_bvlpred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let (a0, a1, a2, a3, a4, a5, a6, a7) = top_pixels(a, x0, y0, stride);
a[y0 * stride + x0] = avg2(a0, a1);
a[(y0 + 1) * stride + x0] = avg3(a0, a1, a2);
a[(y0 + 2) * stride + x0] = avg2(a1, a2);
a[y0 * stride + x0 + 1] = avg2(a1, a2);
a[(y0 + 1) * stride + x0 + 1] = avg3(a1, a2, a3);
a[(y0 + 3) * stride + x0] = avg3(a1, a2, a3);
a[(y0 + 2) * stride + x0 + 1] = avg2(a2, a3);
a[y0 * stride + x0 + 2] = avg2(a2, a3);
a[(y0 + 3) * stride + x0 + 1] = avg3(a2, a3, a4);
a[(y0 + 1) * stride + x0 + 2] = avg3(a2, a3, a4);
a[(y0 + 2) * stride + x0 + 2] = avg2(a3, a4);
a[y0 * stride + x0 + 3] = avg2(a3, a4);
a[(y0 + 3) * stride + x0 + 2] = avg3(a3, a4, a5);
a[(y0 + 1) * stride + x0 + 3] = avg3(a3, a4, a5);
a[(y0 + 2) * stride + x0 + 3] = avg3(a4, a5, a6);
a[(y0 + 3) * stride + x0 + 3] = avg3(a5, a6, a7);
}
fn predict_bhdpred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let (e0, e1, e2, e3, e4, e5, e6, e7, _) = edge_pixels(a, x0, y0, stride);
a[(y0 + 3) * stride + x0] = avg2(e0, e1);
a[(y0 + 3) * stride + x0 + 1] = avg3(e0, e1, e2);
a[(y0 + 2) * stride + x0] = avg2(e1, e2);
a[(y0 + 3) * stride + x0 + 2] = avg2(e1, e2);
a[(y0 + 2) * stride + x0 + 1] = avg3(e1, e2, e3);
a[(y0 + 3) * stride + x0 + 3] = avg3(e1, e2, e3);
a[(y0 + 2) * stride + x0 + 2] = avg2(e2, e3);
a[(y0 + 1) * stride + x0] = avg2(e2, e3);
a[(y0 + 2) * stride + x0 + 3] = avg3(e2, e3, e4);
a[(y0 + 1) * stride + x0 + 1] = avg3(e2, e3, e4);
a[(y0 + 1) * stride + x0 + 2] = avg2(e3, e4);
a[y0 * stride + x0] = avg2(e3, e4);
a[(y0 + 1) * stride + x0 + 3] = avg3(e3, e4, e5);
a[y0 * stride + x0 + 1] = avg3(e3, e4, e5);
a[y0 * stride + x0 + 2] = avg3(e4, e5, e6);
a[y0 * stride + x0 + 3] = avg3(e5, e6, e7);
}
fn predict_bhupred(a: &mut [u8], x0: usize, y0: usize, stride: usize) {
let (l0, l1, l2, l3) = left_pixels(a, x0, y0, stride);
a[y0 * stride + x0] = avg2(l0, l1);
a[y0 * stride + x0 + 1] = avg3(l0, l1, l2);
a[y0 * stride + x0 + 2] = avg2(l1, l2);
a[(y0 + 1) * stride + x0] = avg2(l1, l2);
a[y0 * stride + x0 + 3] = avg3(l1, l2, l3);
a[(y0 + 1) * stride + x0 + 1] = avg3(l1, l2, l3);
a[(y0 + 1) * stride + x0 + 2] = avg2(l2, l3);
a[(y0 + 2) * stride + x0] = avg2(l2, l3);
a[(y0 + 1) * stride + x0 + 3] = avg3(l2, l3, l3);
a[(y0 + 2) * stride + x0 + 1] = avg3(l2, l3, l3);
a[(y0 + 2) * stride + x0 + 2] = l3;
a[(y0 + 2) * stride + x0 + 3] = l3;
a[(y0 + 3) * stride + x0] = l3;
a[(y0 + 3) * stride + x0 + 1] = l3;
a[(y0 + 3) * stride + x0 + 2] = l3;
a[(y0 + 3) * stride + x0 + 3] = l3;
}
#[cfg(all(test, feature = "_benchmarks"))]
mod benches {
use super::*;
use test::{black_box, Bencher};
const W: usize = 256;
const H: usize = 256;
fn make_sample_image() -> Vec<u8> {
let mut v = Vec::with_capacity((W * H * 4) as usize);
for c in 0u8..=255 {
for k in 0u8..=255 {
v.push(c);
v.push(0);
v.push(0);
v.push(k);
}
}
v
}
#[bench]
fn bench_predict_4x4(b: &mut Bencher) {
let mut v = black_box(make_sample_image());
let res_data = vec![1i32; W * H * 4];
let modes = [
IntraMode::TM,
IntraMode::VE,
IntraMode::HE,
IntraMode::DC,
IntraMode::LD,
IntraMode::RD,
IntraMode::VR,
IntraMode::VL,
IntraMode::HD,
IntraMode::HU,
IntraMode::TM,
IntraMode::VE,
IntraMode::HE,
IntraMode::DC,
IntraMode::LD,
IntraMode::RD,
];
b.iter(|| {
black_box(predict_4x4(&mut v, W * 2, &modes, &res_data));
});
}
#[bench]
fn bench_predict_bvepred(b: &mut Bencher) {
let mut v = make_sample_image();
b.iter(|| {
predict_bvepred(black_box(&mut v), 5, 5, W * 2);
});
}
#[bench]
fn bench_predict_bldpred(b: &mut Bencher) {
let mut v = black_box(make_sample_image());
b.iter(|| {
black_box(predict_bldpred(black_box(&mut v), 5, 5, W * 2));
});
}
#[bench]
fn bench_predict_brdpred(b: &mut Bencher) {
let mut v = black_box(make_sample_image());
b.iter(|| {
black_box(predict_brdpred(black_box(&mut v), 5, 5, W * 2));
});
}
#[bench]
fn bench_predict_bhepred(b: &mut Bencher) {
let mut v = black_box(make_sample_image());
b.iter(|| {
black_box(predict_bhepred(black_box(&mut v), 5, 5, W * 2));
});
}
#[bench]
fn bench_top_pixels(b: &mut Bencher) {
let v = black_box(make_sample_image());
b.iter(|| {
black_box(top_pixels(black_box(&v), 5, 5, W * 2));
});
}
#[bench]
fn bench_edge_pixels(b: &mut Bencher) {
let v = black_box(make_sample_image());
b.iter(|| {
black_box(edge_pixels(black_box(&v), 5, 5, W * 2));
});
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_avg2() {
for i in 0u8..=255 {
for j in 0u8..=255 {
let ceil_avg = ((i as f32) + (j as f32)) / 2.0;
let ceil_avg = ceil_avg.ceil() as u8;
assert_eq!(
ceil_avg,
avg2(i, j),
"avg2({}, {}), expected {}, got {}.",
i,
j,
ceil_avg,
avg2(i, j)
);
}
}
}
#[test]
fn test_avg2_specific() {
assert_eq!(
255,
avg2(255, 255),
"avg2(255, 255), expected 255, got {}.",
avg2(255, 255)
);
assert_eq!(1, avg2(1, 1), "avg2(1, 1), expected 1, got {}.", avg2(1, 1));
assert_eq!(2, avg2(2, 1), "avg2(2, 1), expected 2, got {}.", avg2(2, 1));
}
#[test]
fn test_avg3() {
for i in 0u8..=255 {
for j in 0u8..=255 {
for k in 0u8..=255 {
let floor_avg = ((i as f32) + 2.0 * (j as f32) + { k as f32 } + 2.0) / 4.0;
let floor_avg = floor_avg.floor() as u8;
assert_eq!(
floor_avg,
avg3(i, j, k),
"avg3({}, {}, {}), expected {}, got {}.",
i,
j,
k,
floor_avg,
avg3(i, j, k)
);
}
}
}
}
#[test]
fn test_edge_pixels() {
#[rustfmt::skip]
let im = vec![5, 6, 7, 8, 9,
4, 0, 0, 0, 0,
3, 0, 0, 0, 0,
2, 0, 0, 0, 0,
1, 0, 0, 0, 0];
let (e0, e1, e2, e3, e4, e5, e6, e7, e8) = edge_pixels(&im, 1, 1, 5);
assert_eq!(e0, 1);
assert_eq!(e1, 2);
assert_eq!(e2, 3);
assert_eq!(e3, 4);
assert_eq!(e4, 5);
assert_eq!(e5, 6);
assert_eq!(e6, 7);
assert_eq!(e7, 8);
assert_eq!(e8, 9);
}
#[test]
fn test_top_pixels() {
#[rustfmt::skip]
let im = vec![1, 2, 3, 4, 5, 6, 7, 8,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0];
let (e0, e1, e2, e3, e4, e5, e6, e7) = top_pixels(&im, 0, 1, 8);
assert_eq!(e0, 1);
assert_eq!(e1, 2);
assert_eq!(e2, 3);
assert_eq!(e3, 4);
assert_eq!(e4, 5);
assert_eq!(e5, 6);
assert_eq!(e6, 7);
assert_eq!(e7, 8);
}
#[test]
fn test_add_residue() {
let mut pblock = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let rblock = [
-1, -2, -3, -4, 250, 249, 248, 250, -10, -18, -192, -17, -3, 15, 18, 9,
];
let expected: [u8; 16] = [0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 10, 29, 33, 25];
add_residue(&mut pblock, &rblock, 0, 0, 4);
for (&e, &i) in expected.iter().zip(&pblock) {
assert_eq!(e, i);
}
}
#[test]
fn test_predict_bhepred() {
#[rustfmt::skip]
let expected: Vec<u8> = vec![5, 0, 0, 0, 0,
4, 4, 4, 4, 4,
3, 3, 3, 3, 3,
2, 2, 2, 2, 2,
1, 1, 1, 1, 1];
#[rustfmt::skip]
let mut im = vec![5, 0, 0, 0, 0,
4, 0, 0, 0, 0,
3, 0, 0, 0, 0,
2, 0, 0, 0, 0,
1, 0, 0, 0, 0];
predict_bhepred(&mut im, 1, 1, 5);
for (&e, i) in expected.iter().zip(im) {
assert_eq!(e, i);
}
}
#[test]
fn test_predict_brdpred() {
#[rustfmt::skip]
let expected: Vec<u8> = vec![5, 6, 7, 8, 9,
4, 5, 6, 7, 8,
3, 4, 5, 6, 7,
2, 3, 4, 5, 6,
1, 2, 3, 4, 5];
#[rustfmt::skip]
let mut im = vec![5, 6, 7, 8, 9,
4, 0, 0, 0, 0,
3, 0, 0, 0, 0,
2, 0, 0, 0, 0,
1, 0, 0, 0, 0];
predict_brdpred(&mut im, 1, 1, 5);
for (&e, i) in expected.iter().zip(im) {
assert_eq!(e, i);
}
}
#[test]
fn test_predict_bldpred() {
#[rustfmt::skip]
let mut im: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0];
let avg_1 = 2u8;
let avg_2 = 3u8;
let avg_3 = 4u8;
let avg_4 = 5u8;
let avg_5 = 6u8;
let avg_6 = 7u8;
let avg_7 = 8u8;
predict_bldpred(&mut im, 0, 1, 8);
assert_eq!(im[8], avg_1);
assert_eq!(im[9], avg_2);
assert_eq!(im[10], avg_3);
assert_eq!(im[11], avg_4);
assert_eq!(im[16], avg_2);
assert_eq!(im[17], avg_3);
assert_eq!(im[18], avg_4);
assert_eq!(im[19], avg_5);
assert_eq!(im[24], avg_3);
assert_eq!(im[25], avg_4);
assert_eq!(im[26], avg_5);
assert_eq!(im[27], avg_6);
assert_eq!(im[32], avg_4);
assert_eq!(im[33], avg_5);
assert_eq!(im[34], avg_6);
assert_eq!(im[35], avg_7);
}
#[test]
fn test_predict_bvepred() {
#[rustfmt::skip]
let mut im: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0];
let avg_1 = 2u8;
let avg_2 = 3u8;
let avg_3 = 4u8;
let avg_4 = 5u8;
predict_bvepred(&mut im, 1, 1, 9);
assert_eq!(im[10], avg_1);
assert_eq!(im[11], avg_2);
assert_eq!(im[12], avg_3);
assert_eq!(im[13], avg_4);
assert_eq!(im[19], avg_1);
assert_eq!(im[20], avg_2);
assert_eq!(im[21], avg_3);
assert_eq!(im[22], avg_4);
assert_eq!(im[28], avg_1);
assert_eq!(im[29], avg_2);
assert_eq!(im[30], avg_3);
assert_eq!(im[31], avg_4);
assert_eq!(im[37], avg_1);
assert_eq!(im[38], avg_2);
assert_eq!(im[39], avg_3);
assert_eq!(im[40], avg_4);
}
}