nihav_itu: ignore high-profile extradata tail when it is not correct
[nihav.git] / nihav-itu / src / codecs / h264 / decoder_st.rs
index d906e592d6155213d5327e923f98db21fec67e61..fad0dd9ac539a9276b74fa65382e79e7a050fe27 100644 (file)
@@ -1,3 +1,5 @@
+use std::sync::Arc;
+
 use nihav_core::codecs::*;
 use nihav_core::io::bitreader::*;
 
@@ -9,9 +11,9 @@ struct H264Decoder {
     height:     usize,
     num_mbs:    usize,
     nal_len:    u8,
-    sps:        Vec<SeqParameterSet>,
+    sps:        Vec<Arc<SeqParameterSet>>,
     cur_sps:    usize,
-    pps:        Vec<PicParameterSet>,
+    pps:        Vec<Arc<PicParameterSet>>,
     cur_pps:    usize,
 
     skip_mode:      FrameSkipMode,
@@ -104,7 +106,7 @@ impl H264Decoder {
                 let mut br = BitReader::new(&src[..(full_size + 7)/8], BitReaderMode::BE);
                                                     br.skip(8)?;
 
-                let slice_hdr = parse_slice_header(&mut br, &self.sps, &self.pps, is_idr, nal_ref_idc)?;
+                let slice_hdr = parse_slice_header(&mut br, self.sps.as_slice(), self.pps.as_slice(), is_idr, nal_ref_idc)?;
                 validate!(br.tell() < full_size);
                 let full_id;
                 if slice_hdr.first_mb_in_slice == 0 {
@@ -201,27 +203,38 @@ println!("PAFF?");
                     self.cur_pic = Some(PictureInfo {
                             id: slice_hdr.frame_num,
                             full_id,
+                            user_id:    full_id,
+                            time:       NATimeInfo::new(None, None, None, 0, 0),
                             pic_type: slice_hdr.slice_type.to_frame_type(),
                             buf,
                             cur_mb: 0,
                             is_ref: nal_ref_idc != 0,
+                            is_idr,
                             long_term: get_long_term_id(is_idr, &slice_hdr),
-                            mv_info: FrameMV::new(sps.pic_width_in_mbs, sps.pic_height_in_mbs),
+                            mv_info: NABufferRef::new(FrameMV::new(sps.pic_width_in_mbs, sps.pic_height_in_mbs)),
                         });
                 }
 
                 self.transform_8x8_mode = pps.transform_8x8_mode;
 
                 self.sstate.reset(sps.pic_width_in_mbs, sps.pic_height_in_mbs, slice_hdr.first_mb_in_slice);
+
+                let mut dst_pic = if let Some(ref pic) = self.cur_pic {
+                        pic.clone()
+                    } else {
+                        return Err(DecoderError::InvalidData);
+                    };
+                let mut dst_frm = NASimpleVideoFrame::from_video_buf(&mut dst_pic.buf).unwrap();
+                let dst_mv_info = &mut dst_pic.mv_info;
                 if !pps.entropy_coding_mode {
-                    self.has_pic = self.decode_slice_cavlc(&mut br, &slice_hdr, full_size)?;
+                    self.has_pic = self.decode_slice_cavlc(&mut br, &slice_hdr, full_size, &mut dst_frm, dst_mv_info)?;
                 } else {
                     br.align();
-                    let start = (br.tell() / 8) as usize;
+                    let start = br.tell() / 8;
                     let csrc = &src[start..];
                     validate!(csrc.len() >= 2);
                     let mut cabac = CABAC::new(csrc, slice_hdr.slice_type, slice_hdr.slice_qp, slice_hdr.cabac_init_idc as usize)?;
-                    self.has_pic = self.decode_slice_cabac(&mut cabac, &slice_hdr)?;
+                    self.has_pic = self.decode_slice_cabac(&mut cabac, &slice_hdr, &mut dst_frm, dst_mv_info)?;
                 }
             },
              2 => { // slice data partition A
@@ -245,7 +258,7 @@ println!("PAFF?");
              6 => {}, //SEI
              7 => {
                 let sps = parse_sps(&src[1..])?;
-                self.sps.push(sps);
+                self.sps.push(Arc::new(sps));
             },
              8 => {
                 validate!(full_size >= 8 + 16);
@@ -253,7 +266,7 @@ println!("PAFF?");
                 let mut found = false;
                 for stored_pps in self.pps.iter_mut() {
                     if stored_pps.pic_parameter_set_id == pps.pic_parameter_set_id {
-                        *stored_pps = pps.clone();
+                        *stored_pps = Arc::clone(&pps);
                         found = true;
                         break;
                     }
@@ -272,7 +285,7 @@ println!("PAFF?");
 
         Ok(())
     }
-    fn pred_mv(sstate: &mut SliceState, frame_refs: &FrameRefs, mb_info: &mut CurrentMBInfo, cur_id: u16, temporal_mv: bool, direct_8x8: bool) {
+    fn pred_mv(sstate: &mut SliceState, frame_refs: &SimplifiedSliceRefs, mb_info: &mut CurrentMBInfo, cur_id: u16, temporal_mv: bool, direct_8x8: bool) {
         let mb_type = mb_info.mb_type;
         if !mb_type.is_4x4() {
             let (pw, ph) = mb_type.size();
@@ -332,7 +345,7 @@ println!("PAFF?");
         }
     }
     #[allow(clippy::cognitive_complexity)]
-    fn handle_macroblock(&mut self, slice_hdr: &SliceHeader, mb_info: &mut CurrentMBInfo) {
+    fn handle_macroblock(&mut self, slice_hdr: &SliceHeader, mb_info: &mut CurrentMBInfo, slice_refs: &SimplifiedSliceRefs, frm: &mut NASimpleVideoFrame<u8>, mv_info: &mut FrameMV) {
         let pps = &self.pps[self.cur_pps];
 
         let qp_y = mb_info.qp_y;
@@ -357,25 +370,40 @@ println!("PAFF?");
                 mb_info.coeffs[i][0] = mb_info.coeffs[24][i];
             }
         }
-        if !mb_info.transform_size_8x8 {
-            let quant_dc = !mb_info.mb_type.is_intra16x16();
-            for i in 0..16 {
-                if mb_info.coded[i] {
-                    if !tx_bypass {
-                        idct(&mut mb_info.coeffs[i], qp_y, quant_dc);
+        if !tx_bypass {
+            if !mb_info.transform_size_8x8 {
+                let quant_dc = !mb_info.mb_type.is_intra16x16();
+                if quant_dc {
+                    for (coded, coeffs) in mb_info.coded[..16].iter_mut().zip(mb_info.coeffs[..16].iter_mut()) {
+                        if *coded {
+                            idct(coeffs, qp_y);
+                        } else if has_dc {
+                            idct_dc(coeffs, qp_y, quant_dc);
+                            *coded = true;
+                        }
                     }
-                } else if has_dc {
-                    if !tx_bypass {
-                        idct_dc(&mut mb_info.coeffs[i], qp_y, quant_dc);
+                } else {
+                    for (coded, coeffs) in mb_info.coded[..16].iter_mut().zip(mb_info.coeffs[..16].iter_mut()) {
+                        if *coded {
+                            idct_skip_dc(coeffs, qp_y);
+                        } else if has_dc {
+                            idct_dc(coeffs, qp_y, quant_dc);
+                            *coded = true;
+                        }
+                    }
+                }
+            } else {
+                for i in 0..4 {
+                    if mb_info.coded[(i & 1) * 2 + (i & 2) * 4] {
+                        dequant8x8(&mut mb_info.coeffs8x8[i].coeffs, &pps.scaling_list_8x8[!mb_info.mb_type.is_intra() as usize]);
+                        idct8x8(&mut mb_info.coeffs8x8[i].coeffs, qp_y);
                     }
-                    mb_info.coded[i] = true;
                 }
             }
-        } else {
-            for i in 0..4 {
-                if mb_info.coded[(i & 1) * 2 + (i & 2) * 4] && !tx_bypass {
-                    dequant8x8(&mut mb_info.coeffs8x8[i].coeffs, &pps.scaling_list_8x8[!mb_info.mb_type.is_intra() as usize]);
-                    idct8x8(&mut mb_info.coeffs8x8[i].coeffs, qp_y);
+        } else if !mb_info.transform_size_8x8 {
+            for i in 0..16 {
+                if !mb_info.coded[i] && has_dc {
+                    mb_info.coded[i] = true;
                 }
             }
         }
@@ -388,7 +416,7 @@ println!("PAFF?");
                 let blk_no = 16 + chroma * 4 + i;
                 mb_info.coeffs[blk_no][0] = mb_info.chroma_dc[chroma][i];
                 if mb_info.coded[blk_no] {
-                    idct(&mut mb_info.coeffs[blk_no], qp_c, false);
+                    idct_skip_dc(&mut mb_info.coeffs[blk_no], qp_c);
                 } else if mb_info.coeffs[blk_no][0] != 0 {
                     idct_dc(&mut mb_info.coeffs[blk_no], qp_c, false);
                     mb_info.coded[blk_no] = true;
@@ -399,7 +427,7 @@ println!("PAFF?");
             self.sstate.reset_mb_mv();
         }
         if !mb_info.mb_type.is_intra() {
-            Self::pred_mv(&mut self.sstate, &self.frame_refs, mb_info, self.cur_id, self.temporal_mv, self.sps[self.cur_sps].direct_8x8_inference);
+            Self::pred_mv(&mut self.sstate, slice_refs, mb_info, self.cur_id, self.temporal_mv, self.sps[self.cur_sps].direct_8x8_inference);
         }
         if !pps.constrained_intra_pred && mb_info.mb_type != MBType::Intra4x4 && mb_info.mb_type != MBType::Intra8x8 {
             self.sstate.fill_ipred(IntraPredMode::DC);
@@ -407,28 +435,27 @@ println!("PAFF?");
 
         let xpos = self.sstate.mb_x * 16;
         let ypos = self.sstate.mb_y * 16;
-        if let Some(ref mut pic) = self.cur_pic {
-            let mut frm = NASimpleVideoFrame::from_video_buf(&mut pic.buf).unwrap();
-            if mb_info.mb_type != MBType::PCM {
-                let weight_mode = if self.pps[self.cur_pps].weighted_pred && slice_hdr.slice_type.is_p() {
-                        1
-                    } else if slice_hdr.slice_type.is_b() {
-                        self.pps[self.cur_pps].weighted_bipred_idc
-                    } else {
-                        0
-                    };
-                recon_mb(&mut frm, slice_hdr, mb_info, &mut self.sstate, &self.frame_refs, &mut self.mc_dsp, weight_mode);
-            } else {
-                for (dline, src) in frm.data[frm.offset[0] + xpos + ypos * frm.stride[0]..].chunks_mut(frm.stride[0]).take(16).zip(self.ipcm_buf.chunks(16)) {
-                    dline[..16].copy_from_slice(src);
-                }
-                for (dline, src) in frm.data[frm.offset[1] + xpos/2 + ypos/2 * frm.stride[1]..].chunks_mut(frm.stride[1]).take(8).zip(self.ipcm_buf[256..].chunks(8)) {
-                    dline[..8].copy_from_slice(src);
-                }
-                for (dline, src) in frm.data[frm.offset[2] + xpos/2 + ypos/2 * frm.stride[2]..].chunks_mut(frm.stride[2]).take(8).zip(self.ipcm_buf[256 + 64..].chunks(8)) {
-                    dline[..8].copy_from_slice(src);
-                }
+
+        if mb_info.mb_type != MBType::PCM {
+            let weight_mode = if self.pps[self.cur_pps].weighted_pred && slice_hdr.slice_type.is_p() {
+                    1
+                } else if slice_hdr.slice_type.is_b() {
+                    self.pps[self.cur_pps].weighted_bipred_idc
+                } else {
+                    0
+                };
+            recon_mb(frm, slice_hdr, mb_info, &mut self.sstate, slice_refs, &mut self.mc_dsp, weight_mode);
+        } else {
+            for (dline, src) in frm.data[frm.offset[0] + xpos + ypos * frm.stride[0]..].chunks_mut(frm.stride[0]).take(16).zip(self.ipcm_buf.chunks(16)) {
+                dline[..16].copy_from_slice(src);
+            }
+            for (dline, src) in frm.data[frm.offset[1] + xpos/2 + ypos/2 * frm.stride[1]..].chunks_mut(frm.stride[1]).take(8).zip(self.ipcm_buf[256..].chunks(8)) {
+                dline[..8].copy_from_slice(src);
             }
+            for (dline, src) in frm.data[frm.offset[2] + xpos/2 + ypos/2 * frm.stride[2]..].chunks_mut(frm.stride[2]).take(8).zip(self.ipcm_buf[256 + 64..].chunks(8)) {
+                dline[..8].copy_from_slice(src);
+            }
+        }
 /*match mb_info.mb_type {
 MBType::BSkip | MBType::Direct | MBType::B16x16(_) | MBType::B16x8(_, _) | MBType::B8x16(_, _) | MBType::B8x8 => {
  let dstride = frm.stride[0];
@@ -440,32 +467,27 @@ MBType::BSkip | MBType::Direct | MBType::B16x16(_) | MBType::B16x8(_, _) | MBTyp
 },
 _ => {},
 };*/
-            self.sstate.save_ipred_context(&frm);
+        self.sstate.save_ipred_context(frm);
+
+        let mb_pos = self.sstate.mb_x + self.sstate.mb_y * mv_info.mb_stride;
+        let mut mb = FrameMBInfo::new();
+        mb.mb_type = mb_info.mb_type.into();
+        for blk4 in 0..16 {
+            mb.mv[blk4] = self.sstate.get_cur_blk4(blk4).mv;
         }
-        if let Some(ref mut pic) = self.cur_pic {
-            let mv_info = &mut pic.mv_info;
-            let mb_pos = self.sstate.mb_x + self.sstate.mb_y * mv_info.mb_stride;
-            let mut mb = FrameMBInfo::new();
-            mb.mb_type = mb_info.mb_type.into();
-            for blk4 in 0..16 {
-                mb.mv[blk4] = self.sstate.get_cur_blk4(blk4).mv;
-            }
-            for blk8 in 0..4 {
-                mb.ref_poc[blk8] = self.frame_refs.map_refs(self.sstate.get_cur_blk8(blk8).ref_idx);
-                mb.ref_idx[blk8] = self.sstate.get_cur_blk8(blk8).ref_idx;
-            }
-            mv_info.mbs[mb_pos] = mb;
+        for blk8 in 0..4 {
+            mb.ref_poc[blk8] = slice_refs.map_refs(self.sstate.get_cur_blk8(blk8).ref_idx);
+            mb.ref_idx[blk8] = self.sstate.get_cur_blk8(blk8).ref_idx;
         }
+        mv_info.mbs[mb_pos] = mb;
+
         if !self.deblock_skip && self.deblock_mode != 1 {
-            self.sstate.fill_deblock(&self.frame_refs, self.deblock_mode, self.is_s);
-            if let Some(ref mut pic) = self.cur_pic {
-                let mut frm = NASimpleVideoFrame::from_video_buf(&mut pic.buf).unwrap();
-                loop_filter_mb(&mut frm, &self.sstate, self.lf_alpha, self.lf_beta);
-            }
+            self.sstate.fill_deblock(slice_refs, self.deblock_mode, self.is_s);
+            loop_filter_mb(frm, &self.sstate, self.lf_alpha, self.lf_beta);
         }
         self.sstate.next_mb();
     }
-    fn decode_slice_cavlc(&mut self, br: &mut BitReader, slice_hdr: &SliceHeader, full_size: usize) -> DecoderResult<bool> {
+    fn decode_slice_cavlc(&mut self, br: &mut BitReader, slice_hdr: &SliceHeader, full_size: usize, frm: &mut NASimpleVideoFrame<u8>, mv_info: &mut FrameMV) -> DecoderResult<bool> {
         const INTRA_CBP: [u8; 48] = [
             47, 31, 15,  0, 23, 27, 29, 30,  7, 11, 13, 14, 39, 43, 45, 46,
             16,  3,  5, 10, 12, 19, 21, 26, 28, 35, 37, 42, 44,  1,  2,  4,
@@ -477,9 +499,13 @@ _ => {},
             17, 18, 20, 24, 19, 21, 26, 28, 23, 27, 29, 30, 22, 25, 38, 41
         ];
 
-        let mut mb_idx = slice_hdr.first_mb_in_slice as usize;
+        let mut mb_idx = slice_hdr.first_mb_in_slice;
         let mut mb_info = CurrentMBInfo { qp_y: slice_hdr.slice_qp, ..Default::default() };
         let skip_type = if slice_hdr.slice_type.is_p() { MBType::PSkip } else { MBType::BSkip };
+
+        let slice_refs = self.frame_refs.cur_refs.clone();
+        let sslice_refs = SimplifiedSliceRefs::new(&slice_refs);
+
         while br.tell() < full_size && mb_idx < self.num_mbs {
             mb_info.coded = [false; 25];
             mb_info.ref_l0 = [ZERO_REF; 4];
@@ -495,7 +521,7 @@ _ => {},
                 validate!(mb_idx + mb_skip_run <= self.num_mbs);
                 mb_info.mb_type = skip_type;
                 for _ in 0..mb_skip_run {
-                    self.handle_macroblock(slice_hdr, &mut mb_info);
+                    self.handle_macroblock(slice_hdr, &mut mb_info, &sslice_refs, frm, mv_info);
                     mb_idx += 1;
                 }
                 if mb_idx == self.num_mbs || br.tell() >= full_size {
@@ -561,7 +587,7 @@ _ => {},
                         decode_residual_cavlc(br, &mut self.sstate, &mut mb_info, &self.cavlc_cb)?;
                     }
                 }
-                self.handle_macroblock(slice_hdr, &mut mb_info);
+                self.handle_macroblock(slice_hdr, &mut mb_info, &sslice_refs, frm, mv_info);
             }
             mb_idx += 1;
         }
@@ -570,14 +596,17 @@ _ => {},
         }
         Ok(mb_idx == self.num_mbs)
     }
-    fn decode_slice_cabac(&mut self, cabac: &mut CABAC, slice_hdr: &SliceHeader) -> DecoderResult<bool> {
-        let mut mb_idx = slice_hdr.first_mb_in_slice as usize;
+    fn decode_slice_cabac(&mut self, cabac: &mut CABAC, slice_hdr: &SliceHeader, frm: &mut NASimpleVideoFrame<u8>, mv_info: &mut FrameMV) -> DecoderResult<bool> {
+        let mut mb_idx = slice_hdr.first_mb_in_slice;
         let mut prev_mb_skipped = false;
         let skip_type = if slice_hdr.slice_type.is_p() { MBType::PSkip } else { MBType::BSkip };
         let mut last_qp_diff = false;
 
         let mut mb_info = CurrentMBInfo { qp_y: slice_hdr.slice_qp, ..Default::default() };
 
+        let slice_refs = self.frame_refs.cur_refs.clone();
+        let sslice_refs = SimplifiedSliceRefs::new(&slice_refs);
+
         while mb_idx < self.num_mbs {
             mb_info.coded = [false; 25];
             mb_info.ref_l0 = [ZERO_REF; 4];
@@ -666,7 +695,7 @@ _ => {},
                 mb_info.transform_size_8x8 = false;
                 last_qp_diff = false;
             }
-            self.handle_macroblock(slice_hdr, &mut mb_info);
+            self.handle_macroblock(slice_hdr, &mut mb_info, &sslice_refs, frm, mv_info);
             prev_mb_skipped = mb_skip;
             if !(self.is_mbaff && ((mb_idx & 1) == 0)) && cabac.decode_terminate() {
                 if let Some(ref mut pic) = self.cur_pic {
@@ -727,7 +756,10 @@ impl NADecoder for H264Decoder {
                     match profile {
                         100 | 110 | 122 | 144 => {
                             let b       = br.read_byte()?;
-                            validate!((b & 0xFC) == 0xFC);
+                            // some encoders put something different here
+                            if (b & 0xFC) != 0xFC {
+                                return Ok(());
+                            }
                             // b & 3 -> chroma format
                             let b       = br.read_byte()?;
                             validate!((b & 0xF8) == 0xF8);
@@ -758,7 +790,7 @@ impl NADecoder for H264Decoder {
             }
 
             let num_bufs = if !self.sps.is_empty() {
-                    self.sps[0].num_ref_frames as usize + 1
+                    self.sps[0].num_ref_frames + 1
                 } else {
                     3
                 }.max(16 + 1);