]>
Commit | Line | Data |
---|---|---|
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 | ]; |