private void ParseSliceGroupMap(INalUnitReader reader, IState resultState, IPictureStateBuilder builder, uint sliceGroupCount) { var sliceGroupMapType = (SliceGroupMapType)reader.GetExpGolombCoded(Attribute.SliceGroupMapType, _sliceGroupMapTypeFormatter); // slice_group_map_type builder.SliceGroupMapType = sliceGroupMapType; switch (sliceGroupMapType) { case SliceGroupMapType.InterleavedSliceGroups: uint[] runLengthMinus1 = new uint[sliceGroupCount]; for (int iGroup = 0; iGroup < sliceGroupCount; iGroup++) { runLengthMinus1[iGroup] = reader.GetExpGolombCoded(); // run_length_minus1[iGroup] } builder.RunLengthMinus1 = runLengthMinus1; break; case SliceGroupMapType.DispersedSliceGroups: break; case SliceGroupMapType.ForegroundAndLeftoverSliceGroups: uint[] topLeft = new uint[sliceGroupCount - 1]; uint[] bottomRight = new uint[sliceGroupCount - 1]; for (int iGroup = 0; iGroup < (sliceGroupCount - 1); iGroup++) { topLeft[iGroup] = reader.GetExpGolombCoded(); bottomRight[iGroup] = reader.GetExpGolombCoded(); } builder.TopLeft = topLeft; builder.BottomRight = bottomRight; break; case SliceGroupMapType.ChangingSliceGroups3: case SliceGroupMapType.ChangingSliceGroups4: case SliceGroupMapType.ChangingSliceGroups5: builder.SliceGroupChangeDirectionFlag = reader.GetBit(); builder.SliceGroupChangeRateMinus1 = reader.GetExpGolombCoded(); break; case SliceGroupMapType.ExplicitSliceGroups: uint pictureSizeInMapUnits = 1 + reader.GetExpGolombCoded(); // pic_size_in_map_units_minus1 int syntaxElementSize = DetectorUtils.Log2(sliceGroupCount - 1) + 1; uint[] sliceGroupId = new uint[pictureSizeInMapUnits]; for (int i = 0; i < pictureSizeInMapUnits; i++) { sliceGroupId[i] = reader.GetBits(syntaxElementSize); } builder.SliceGroupId = sliceGroupId; break; default: resultState.Invalidate(); break; } }
// 7.3.3 Slice header syntax public void Parse(INalUnitReader reader, IResultNodeState resultState) { reader.State.SliceState = null; // Invalid, unless the slice header is valid! uint firstMacroblockInSlice = reader.GetExpGolombCoded(Attribute.FirstMacroblockInSlice, uint.MaxValue); // first_mb_in_slice #if DEBUG H264Debug.WriteLine("+ first_mb_in_slice={0}", firstMacroblockInSlice); #endif SliceType pictureSliceType = (SliceType)reader.GetExpGolombCoded(Attribute.SliceType, _sliceTypeResultFormatter); SliceType sliceType = (SliceType)((int)pictureSliceType % 5); #if DEBUG H264Debug.WriteLine("+ slice_type={0}", (int)sliceType); #endif byte pictureParamaterSetId = (byte)reader.GetExpGolombCoded(Attribute.PictureParameterSetId, 255); #if DEBUG H264Debug.WriteLine("+ pic_parameter_set_id={0}", pictureParamaterSetId); #endif var pictureState = reader.State.PictureStates[pictureParamaterSetId]; if (pictureState == null) { if (resultState.Valid) { if (IsFalseHit(firstMacroblockInSlice, sliceType, pictureParamaterSetId) || (pictureParamaterSetId > 10)) { resultState.Invalidate(); } } return; // cannot validate slice header!! } ISliceStateBuilder builder = new SliceStateBuilder(pictureState); builder.FirstMacroBlockInSlice = firstMacroblockInSlice; builder.SliceType = sliceType; if (pictureState.PictureSliceType.HasValue && (sliceType != pictureState.PictureSliceType)) { // FIXME: This rule only applies to slices within a single picture. // Since we currently don't detect whether this slice starts a // new picture, we have to disable this rule for now! // oldIReaderState.Invalidate(); // return; } if (/*!pictureState.PictureSliceType.HasValue && */ sliceType != pictureSliceType) { pictureState.PictureSliceType = pictureSliceType; } if (IsNonIntraSliceInIntraCodedPicture(reader, sliceType, pictureState)) { resultState.Invalidate(); return; } var sequenceState = pictureState.SequenceState; if (sequenceState.ChromaFormat == ChromaFormat.SeparateColorPlane) { reader.GetBits(2, Attribute.ColorPlane, _colorPlaneResultFormatter); // colour_plane_id } ParseFrameNum(reader, sequenceState); bool fieldPicFlag = false; if (!sequenceState.FrameMbsOnlyFlag) { fieldPicFlag = reader.GetBit(); // field_pic_flag builder.FieldPicFlag = fieldPicFlag; if (fieldPicFlag) { reader.GetBit(); // bottom_field_flag } } if (reader.State.IdrPicFlag) { reader.GetExpGolombCoded(Attribute.IdrPictureId, 65535); // idr_pic_id } if (sequenceState.PictureOrderCountType == 0) { reader.GetBits((int)sequenceState.Log2MaxPicOrderCntLsb); // pic_order_cnt_lsb if (pictureState.PictureOrderPresent && !fieldPicFlag) { reader.GetSignedExpGolombCoded(); // delta_pic_order_cnt_bottom } } else if ((sequenceState.PictureOrderCountType == 1) && !sequenceState.DeltaPicOrderAlwaysZeroFlag) { reader.GetSignedExpGolombCoded(); // delta_pic_order_cnt_0 if (pictureState.PictureOrderPresent && !fieldPicFlag) { reader.GetSignedExpGolombCoded(); // delta_pic_order_cnt_1 } } if (pictureState.RedundantPictureControlPresent) { reader.GetExpGolombCoded(Attribute.RedundantPictureCounter, 127); // redundant_pic_cnt } if (sliceType == SliceType.B) { reader.GetBit(); // direct_spatial_mv_pred_flag } uint activeReferencePictureCount0 = pictureState.DefaultReferencePictureCount0; uint activeReferencePictureCount1 = pictureState.DefaultReferencePictureCount1; if (!IsIntraCoded(sliceType) && reader.GetBit()) // num_ref_idx_active_override_flag { uint maxRefIdxActiveMinus1 = fieldPicFlag ? 31U : 15U; activeReferencePictureCount0 = reader.GetExpGolombCoded(maxRefIdxActiveMinus1) + 1; // num_ref_idx_l0_active_minus1 if (sliceType == SliceType.B) { activeReferencePictureCount1 = reader.GetExpGolombCoded(maxRefIdxActiveMinus1) + 1; // num_ref_idx_l1_active_minus1 } } builder.ActiveReferencePictureCount0 = activeReferencePictureCount0; builder.ActiveReferencePictureCount1 = activeReferencePictureCount1; RefPicListModification(reader, resultState, sliceType); if ((pictureState.WeightedPrediction && (sliceType == SliceType.P || sliceType == SliceType.Sp)) || (pictureState.WeightedBidirectionalPrediction == WeightedBidirectionalPredictionType.ExplicitWeightedPrediction && sliceType == SliceType.B)) { PredWeightTable(reader, sequenceState, sliceType, activeReferencePictureCount0, activeReferencePictureCount1); } if (reader.State.NalRefIdc != 0) { DecRefPicMarking(reader, resultState); } if (pictureState.EntropyCodingMode && !IsIntraCoded(sliceType)) { builder.CabacInitIdc = reader.GetExpGolombCoded(2U); } builder.SliceQpDelta = reader.GetSignedExpGolombCoded(); if ((sliceType == SliceType.Sp) || (sliceType == SliceType.Si)) { if (sliceType == SliceType.Sp) { reader.GetBit(); // sp_for_switch_flag } reader.GetSignedExpGolombCoded(); // slice_qs_delta } if (pictureState.DeblockingFilterControlPresent) { uint disableDeblockingFilterIdc = reader.GetExpGolombCoded(); // disable_deblocking_filter_idc if (disableDeblockingFilterIdc != 1) { reader.GetSignedExpGolombCoded(); // slice_alpha_c0_offset_div2 reader.GetSignedExpGolombCoded(); // slice_beta_offset_div2 } } if (pictureState.SliceGroupCount > 1 && pictureState.SliceGroupMapType >= SliceGroupMapType.ChangingSliceGroups3 && pictureState.SliceGroupMapType <= SliceGroupMapType.ChangingSliceGroups5) { uint value = (sequenceState.PicSizeInMapUnits / pictureState.SliceGroupChangeRate); int requiredBitsToRepresentValue = DetectorUtils.Log2(value) + 1; builder.SliceGroupChangeCycle = reader.GetBits(requiredBitsToRepresentValue); // slice_group_change_cycle; } // Check 'firstMacroblockInSlice' field uint picHeightInMbs = sequenceState.FrameHeightInMbs / (fieldPicFlag ? 2U : 1U); uint picSizeInMbs = sequenceState.PicWidthInMbs * picHeightInMbs; bool mbAffFrameFlag = sequenceState.MbAdaptiveFrameFieldFlag && !fieldPicFlag; if ((firstMacroblockInSlice * (mbAffFrameFlag ? 2U : 1U)) >= picSizeInMbs) { resultState.Invalidate(); } if (resultState.Valid) { // Since the 'pictureParameterSetId' is probably correct at this point, // we prevent the check for 'pictureParameterSetId > 10'. if (IsFalseHit(firstMacroblockInSlice, sliceType, Math.Min((byte)1, pictureParamaterSetId))) { resultState.Invalidate(); } else { reader.State.SliceState = builder.Build(); } } }