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