| 1 | /* |
| 2 | known bugs and limitations: |
| 3 | * wrong slice boundary filtering |
| 4 | * not fully correct deblock strength selection for P/B-macroblocks |
| 5 | * scaling lists for 4x4 blocks |
| 6 | */ |
| 7 | use nihav_core::codecs::*; |
| 8 | use nihav_core::io::byteio::*; |
| 9 | use nihav_core::io::bitreader::*; |
| 10 | use nihav_core::io::intcode::*; |
| 11 | use nihav_codec_support::codecs::{MV, ZERO_MV}; |
| 12 | |
| 13 | mod types; |
| 14 | pub use types::*; |
| 15 | mod pic_ref; |
| 16 | pub use pic_ref::*; |
| 17 | #[allow(clippy::identity_op)] |
| 18 | #[allow(clippy::erasing_op)] |
| 19 | #[allow(clippy::many_single_char_names)] |
| 20 | #[allow(clippy::range_plus_one)] |
| 21 | mod dsp; |
| 22 | use dsp::*; |
| 23 | mod cabac; |
| 24 | use cabac::*; |
| 25 | mod cabac_coder; |
| 26 | use cabac_coder::*; |
| 27 | mod cavlc; |
| 28 | use cavlc::*; |
| 29 | mod loopfilter; |
| 30 | use loopfilter::*; |
| 31 | mod mb_recon; |
| 32 | use mb_recon::*; |
| 33 | mod sets; |
| 34 | use sets::*; |
| 35 | mod slice; |
| 36 | use slice::*; |
| 37 | |
| 38 | mod decoder_st; |
| 39 | pub use decoder_st::*; |
| 40 | |
| 41 | trait ReadUE { |
| 42 | fn read_ue(&mut self) -> DecoderResult<u32>; |
| 43 | fn read_te(&mut self, range: u32) -> DecoderResult<u32>; |
| 44 | fn read_ue_lim(&mut self, max_val: u32) -> DecoderResult<u32> { |
| 45 | let val = self.read_ue()?; |
| 46 | validate!(val <= max_val); |
| 47 | Ok(val) |
| 48 | } |
| 49 | fn read_se(&mut self) -> DecoderResult<i32> { |
| 50 | let val = self.read_ue()?; |
| 51 | if (val & 1) != 0 { |
| 52 | Ok (((val >> 1) as i32) + 1) |
| 53 | } else { |
| 54 | Ok (-((val >> 1) as i32)) |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | impl<'a> ReadUE for BitReader<'a> { |
| 60 | fn read_ue(&mut self) -> DecoderResult<u32> { |
| 61 | Ok(self.read_code(UintCodeType::GammaP)? - 1) |
| 62 | } |
| 63 | fn read_te(&mut self, range: u32) -> DecoderResult<u32> { |
| 64 | if range == 1 { |
| 65 | if self.read_bool()? { |
| 66 | Ok(0) |
| 67 | } else { |
| 68 | Ok(1) |
| 69 | } |
| 70 | } else { |
| 71 | let val = self.read_ue()?; |
| 72 | validate!(val <= range); |
| 73 | Ok(val) |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | #[derive(Clone,Copy)] |
| 79 | pub struct Coeff8x8 { |
| 80 | pub coeffs: [i16; 64], |
| 81 | } |
| 82 | |
| 83 | impl Coeff8x8 { |
| 84 | fn clear(&mut self) { |
| 85 | self.coeffs = [0; 64]; |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | impl Default for Coeff8x8 { |
| 90 | fn default() -> Self { |
| 91 | Self { |
| 92 | coeffs: [0; 64], |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | #[derive(Clone,Copy,Default)] |
| 98 | pub struct CurrentMBInfo { |
| 99 | pub mb_type: MBType, |
| 100 | pub sub_mb_type: [SubMBType; 4], |
| 101 | pub ipred: [IntraPredMode; 16], |
| 102 | pub chroma_ipred: u8, |
| 103 | pub luma_ipred: [u8; 16], |
| 104 | pub mv_l0: [MV; 16], |
| 105 | pub ref_l0: [PicRef; 4], |
| 106 | pub mv_l1: [MV; 16], |
| 107 | pub ref_l1: [PicRef; 4], |
| 108 | pub qp_y: u8, |
| 109 | pub cbpy: u8, |
| 110 | pub cbpc: u8, |
| 111 | pub coeffs: [[i16; 16]; 25], |
| 112 | pub coeffs8x8: [Coeff8x8; 4], |
| 113 | pub chroma_dc: [[i16; 4]; 2], |
| 114 | pub coded: [bool; 25], |
| 115 | pub transform_size_8x8: bool, |
| 116 | } |
| 117 | |
| 118 | impl CurrentMBInfo { |
| 119 | fn clear_coeffs8x8(&mut self) { |
| 120 | for c in self.coeffs8x8.iter_mut() { |
| 121 | c.clear(); |
| 122 | } |
| 123 | } |
| 124 | fn can_have_8x8_tx(&self, inference_flag: bool) -> bool { |
| 125 | match self.mb_type { |
| 126 | MBType::Intra4x4 | MBType::Intra8x8 | MBType::Intra16x16(_, _, _) | MBType::PCM => false, |
| 127 | MBType::P8x8 | MBType::P8x8Ref0 | MBType::B8x8 => { |
| 128 | for &sub_id in self.sub_mb_type.iter() { |
| 129 | match sub_id { |
| 130 | SubMBType::P8x8 | |
| 131 | SubMBType::B8x8(_) |
| 132 | => {}, |
| 133 | SubMBType::Direct8x8 |
| 134 | => if !inference_flag { return false; }, |
| 135 | _ => return false, |
| 136 | }; |
| 137 | } |
| 138 | true |
| 139 | }, |
| 140 | MBType::Direct => inference_flag, |
| 141 | _ => true, |
| 142 | } |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | fn get_long_term_id(is_idr: bool, slice_hdr: &SliceHeader) -> Option<usize> { |
| 147 | if is_idr && !slice_hdr.long_term_reference { |
| 148 | None |
| 149 | } else { |
| 150 | let marking = &slice_hdr.adaptive_ref_pic_marking; |
| 151 | for (&op, &arg) in marking.memory_management_control_op.iter().zip(marking.operation_arg.iter()).take(marking.num_ops) { |
| 152 | if op == 6 { |
| 153 | return Some(arg as usize); |
| 154 | } |
| 155 | } |
| 156 | None |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | fn unescape_nal(src: &[u8], dst: &mut Vec<u8>) -> usize { |
| 161 | let mut off = 0; |
| 162 | let mut zrun = 0; |
| 163 | dst.clear(); |
| 164 | dst.reserve(src.len()); |
| 165 | while off < src.len() { |
| 166 | dst.push(src[off]); |
| 167 | if src[off] != 0 { |
| 168 | zrun = 0; |
| 169 | } else { |
| 170 | zrun += 1; |
| 171 | if zrun == 2 && off + 1 < src.len() && src[off + 1] == 0x03 { |
| 172 | zrun = 0; |
| 173 | off += 1; |
| 174 | } |
| 175 | if zrun >= 3 && off + 1 < src.len() && src[off + 1] == 0x01 { |
| 176 | off -= 3; |
| 177 | dst.truncate(off); |
| 178 | break; |
| 179 | } |
| 180 | } |
| 181 | off += 1; |
| 182 | } |
| 183 | off |
| 184 | } |
| 185 | |
| 186 | const DEBLOCK_SKIP_OPTION: &str = "skip_deblock"; |
| 187 | |
| 188 | const DECODER_OPTIONS: &[NAOptionDefinition] = &[ |
| 189 | NAOptionDefinition { |
| 190 | name: FRAME_SKIP_OPTION, description: FRAME_SKIP_OPTION_DESC, |
| 191 | opt_type: NAOptionDefinitionType::Bool }, |
| 192 | NAOptionDefinition { |
| 193 | name: DEBLOCK_SKIP_OPTION, description: "Loop filter skipping mode", |
| 194 | opt_type: NAOptionDefinitionType::String(Some(&[ |
| 195 | FRAME_SKIP_OPTION_VAL_NONE, |
| 196 | FRAME_SKIP_OPTION_VAL_KEYFRAME, |
| 197 | FRAME_SKIP_OPTION_VAL_INTRA |
| 198 | ])) }, |
| 199 | ]; |
| 200 | |
| 201 | #[cfg(test)] |
| 202 | mod test { |
| 203 | use nihav_core::codecs::RegisteredDecoders; |
| 204 | use nihav_core::demuxers::RegisteredDemuxers; |
| 205 | use nihav_codec_support::test::dec_video::*; |
| 206 | use crate::itu_register_all_decoders; |
| 207 | use nihav_commonfmt::generic_register_all_demuxers; |
| 208 | |
| 209 | // samples if not specified otherwise come from H.264 conformance suite |
| 210 | mod raw_demux; |
| 211 | mod conformance; |
| 212 | use self::raw_demux::RawH264DemuxerCreator; |
| 213 | |
| 214 | #[test] |
| 215 | fn test_h264_perframe() { |
| 216 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 217 | dmx_reg.add_demuxer(&RawH264DemuxerCreator{}); |
| 218 | generic_register_all_demuxers(&mut dmx_reg); |
| 219 | let mut dec_reg = RegisteredDecoders::new(); |
| 220 | itu_register_all_decoders(&mut dec_reg); |
| 221 | |
| 222 | test_decoding("rawh264", "h264", |
| 223 | "assets/ITU/h264-conformance/CABAST3_Sony_E.jsv", |
| 224 | None, &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ |
| 225 | [0xb5e5e368, 0x6ac59bfc, 0x82e35b7b, 0xbed17b81], |
| 226 | [0x8343b34d, 0x0de80ae9, 0xe9c08cc9, 0x05161d82], |
| 227 | [0x26e08b9b, 0x84949759, 0x71622124, 0x9bfff254], |
| 228 | [0x940c38bc, 0x559fb990, 0x2b82a7ca, 0x3543188a], |
| 229 | [0x60d7544d, 0x2fc8cc23, 0x4acac90f, 0x44c2a91c], |
| 230 | [0x68d86265, 0x15fc15b9, 0xe4946d83, 0x39d9584d], |
| 231 | [0xaed8e194, 0xa24b3a8a, 0xbed9085d, 0x05d68293], |
| 232 | [0x1cddffac, 0x0ce9d209, 0xc4090b8a, 0xc3008856], |
| 233 | [0x42ee0e5e, 0x4c1c3b64, 0xd91cc00b, 0x88be4b15], |
| 234 | [0x19a70aa8, 0xd8bc987d, 0x51c04849, 0x71191523], |
| 235 | [0x74532da6, 0xecb92919, 0xd39cb150, 0x9ca9933d], |
| 236 | [0x0444b315, 0x2ddfb91a, 0x1e21ce06, 0x0c8613e6], |
| 237 | [0xce209363, 0xf8d8331f, 0x72e0102f, 0x88de3a97], |
| 238 | [0xdbcfa40a, 0x7eed5940, 0xa5c53a66, 0xdfcd3cea], |
| 239 | [0x00796b14, 0x58f16117, 0xb6a5efd1, 0xfb129acd], |
| 240 | [0x7673f569, 0xfccfb96a, 0x1f614c82, 0xf62ea376], |
| 241 | [0x8669d98b, 0x9fdf4e7d, 0xa4083a7f, 0x9b66d296], |
| 242 | [0xf0537976, 0x924229ab, 0xd0f4612f, 0xad4b614e], |
| 243 | [0xbde82067, 0x6cf23a0c, 0xdd29e64d, 0xcaa72ff3], |
| 244 | [0xcfcb544a, 0x1f1a81b0, 0x2217108c, 0x4888d5ef], |
| 245 | [0x3369f874, 0x6a6dde75, 0x46d64780, 0xbf6ced32], |
| 246 | [0x253a1f45, 0x85954311, 0x983dbabe, 0x658f4ce3], |
| 247 | [0xec97b332, 0xa17b26d0, 0xbead22af, 0xa6bd7d8e], |
| 248 | [0x5673d973, 0x78528036, 0xabfe5e13, 0xdcedfb26], |
| 249 | [0xd6110fa9, 0x532d6a30, 0xb7f0aa7c, 0xae7b544b]])); |
| 250 | } |
| 251 | |
| 252 | // mostly static music video downloaded with youtube-dl |
| 253 | #[test] |
| 254 | fn test_h264_real1() { |
| 255 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 256 | dmx_reg.add_demuxer(&RawH264DemuxerCreator{}); |
| 257 | generic_register_all_demuxers(&mut dmx_reg); |
| 258 | let mut dec_reg = RegisteredDecoders::new(); |
| 259 | itu_register_all_decoders(&mut dec_reg); |
| 260 | |
| 261 | test_decoding("mov", "h264", "assets/ITU/1.mp4", |
| 262 | Some(60), &dmx_reg, &dec_reg, |
| 263 | ExpectedTestResult::MD5Frames(vec![ |
| 264 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 265 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 266 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 267 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 268 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 269 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 270 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 271 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 272 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 273 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 274 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 275 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 276 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 277 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 278 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 279 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 280 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 281 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 282 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 283 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 284 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 285 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 286 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 287 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 288 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 289 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 290 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 291 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 292 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 293 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 294 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 295 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 296 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 297 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 298 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 299 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 300 | [0x9dbac04a, 0xc49ca8c1, 0x09bb9182, 0xc7928970], |
| 301 | [0xc54f1b6e, 0xaba56a71, 0x8b45132b, 0x3c8bde7f], |
| 302 | [0xe2742374, 0x7b9d6fa6, 0xd57eb3bb, 0x42986664], |
| 303 | [0xa5ebdc2e, 0x9753a46a, 0x631c6359, 0x861ae0e3], |
| 304 | [0x4d2c8769, 0xb9e15141, 0x03274d1f, 0xc15a3733], |
| 305 | [0x17ebec8f, 0xe417571e, 0x75eb2559, 0x2f9b882b], |
| 306 | [0x148e8c97, 0x778f92ba, 0x93646539, 0xeebe643a], |
| 307 | [0xc6770caa, 0x1ac11a57, 0x1388a550, 0x2347758e], |
| 308 | [0x91eb3ae4, 0xaf664462, 0x858d344a, 0xda3baa79], |
| 309 | [0x4de79514, 0x3597aff0, 0x53e1a22f, 0x7875aa4c], |
| 310 | [0xd5afcf7c, 0xa0f4ce82, 0x21a70eb2, 0x3911cde1], |
| 311 | [0x9efa2a08, 0x29019ca6, 0xaba90890, 0xfb982857], |
| 312 | [0xc5755e20, 0x4c66cb54, 0x1194812e, 0x11a9d940], |
| 313 | [0xfd131bbb, 0x0acefb02, 0x6c79b7ab, 0x35bcdd26], |
| 314 | [0xad159db0, 0xfa65ced2, 0xf77e2b22, 0x9e6283a8], |
| 315 | [0xba2059e3, 0xc9f1e5e7, 0x7ea5fbcb, 0xf48d4fc3], |
| 316 | [0xbe794078, 0x64d69f9b, 0x7b6355c5, 0x7dfb5b0f], |
| 317 | [0x6031b77b, 0x712f42fd, 0x30d423df, 0x740e488c], |
| 318 | [0xcc475484, 0x30a664fc, 0x227a9725, 0x4b2bfb18], |
| 319 | [0x44bef2ea, 0xaf1e69e8, 0x832d94a8, 0xffb22712], |
| 320 | [0xe9471e3d, 0x103de80f, 0xdc44136f, 0x67dacaa8], |
| 321 | [0x4df3823d, 0xf6486ca9, 0x016f3114, 0x1c2d0b42], |
| 322 | [0x1171666b, 0x08ca0ced, 0x98719757, 0xbd6b4a86], |
| 323 | [0x9d2fc556, 0x5569fbbd, 0x0ebf629f, 0xd4fdc3b5], |
| 324 | [0x27dbd3c3, 0x803f0230, 0x13f2ff1b, 0xb661b622]])); |
| 325 | } |
| 326 | // a sample downloaded from gfycat.com |
| 327 | #[test] |
| 328 | fn test_h264_real2() { |
| 329 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 330 | dmx_reg.add_demuxer(&RawH264DemuxerCreator{}); |
| 331 | generic_register_all_demuxers(&mut dmx_reg); |
| 332 | let mut dec_reg = RegisteredDecoders::new(); |
| 333 | itu_register_all_decoders(&mut dec_reg); |
| 334 | test_decoding("mov", "h264", "assets/ITU/DimpledSpanishCuckoo-mobile.mp4", |
| 335 | Some(10), &dmx_reg, &dec_reg, |
| 336 | ExpectedTestResult::MD5Frames(vec![ |
| 337 | [0x674c6d60, 0xc7ab918d, 0x9db1beaf, 0xda9f2456], |
| 338 | [0x6a935350, 0x3d463ab2, 0xa3ab3c53, 0x97eb896b], |
| 339 | [0xf6c60411, 0x19ea2c49, 0x3512371a, 0xce6cb26a], |
| 340 | [0xc87afeaa, 0x79899908, 0x152e6320, 0xe689827f], |
| 341 | [0xa3d829e3, 0xb404dd32, 0x11983613, 0xbdf10ee6], |
| 342 | [0x2440ea01, 0x5b9d7fc7, 0x4fa5632b, 0xd2d76090], |
| 343 | [0xd80e8bf9, 0xe9190ab7, 0x2be8fa38, 0xb94182e8], |
| 344 | [0x50b9fd9a, 0x64393126, 0xd03162ec, 0xfb54172a], |
| 345 | [0x80d1f58f, 0x12e454c0, 0x2140ca5c, 0xe19350ba], |
| 346 | [0x26078d38, 0xf6a59d57, 0xcd14eaf8, 0x8eb08259], |
| 347 | [0x31494337, 0x6f8d3f52, 0x4bc9ff92, 0x0c601b1c]])); |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | pub const I4X4_SCAN: [(u8, u8); 16] = [ |
| 352 | (0,0), (1,0), (0,1), (1,1), (2,0), (3,0), (2,1), (3,1), |
| 353 | (0,2), (1,2), (0,3), (1,3), (2,2), (3,2), (2,3), (3,3) |
| 354 | ]; |