public void Parse(INalUnitReader reader, IResultNodeState resultState) { reader.GetFixedBits(1, 0, Attribute.ForbiddenZeroBit); reader.State.NalRefIdc = reader.GetBits(2, Attribute.NalRefIdc); reader.State.NalUnitType = (NalUnitType)reader.GetBits(5, Attribute.NalUnitType); INalUnitPayloadParser nalUnitPayloadParser; if (!_nalUnitParsers.TryGetValue(reader.State.NalUnitType, out nalUnitPayloadParser)) { resultState.Invalidate(); return; } //Parse remainder with specific nalunitparser (NOTE: Is not a sub-object) nalUnitPayloadParser.Parse(reader, resultState); if (!resultState.Valid) { return; // Stop processing of invalid NAL unit. } if (!CanParseNalUnitType(reader.State.SliceState, reader.State.NalUnitType)) { // Forward to the estimated end of the NAL unit reader.Position = reader.Length; resultState.Invalidate(); // Invalidates the result resultState.Recover(); // Revalidates the reader state so parsing can continue! return; } if (reader.State.NalUnitType == NalUnitType.SequenceParameterSet) { return; // Note: SPS validate their own data! } if (reader.State.NalUnitType == NalUnitType.PictureParameterSet) { return; // Note: PPS validate their own data! } if (!IsSlice(reader.State.NalUnitType) || !reader.State.SliceState.PictureState.EntropyCodingMode) { if (reader.GetBits(1) != 1) // rbsp_stop_one_bit (equal to 1) { resultState.Invalidate(); return; } } if (IsSlice(reader.State.NalUnitType) && resultState.Valid) { return; // Random (e.g. audio) data is allowed after a valid slice } reader.ReadZeroAlignmentBits(); }
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; } }
private static void GetHrdParameters(INalUnitReader reader, IState resultState) { uint cpbCntMinus1 = reader.GetExpGolombCoded(); // cpb_cnt_minus1 reader.GetBits(4); // bit_rate_scale reader.GetBits(4); // cpb_size_scale // for (SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++) for (int schedSelIdx = 0; schedSelIdx <= cpbCntMinus1; schedSelIdx++) { if (!reader.HasMoreRbspData()) { resultState.Invalidate(); return; } reader.GetExpGolombCoded(); // bit_rate_value_minus1[SchedSelIdx] reader.GetExpGolombCoded(); // cpb_size_value_minus1[SchedSelIdx] reader.GetBit(); // cbr_flag[SchedSelIdx] } reader.GetBits(5); // initial_cpb_removal_delay_length_minus1 reader.GetBits(5); // cpb_removal_delay_length_minus1 reader.GetBits(5); // dpb_output_delay_length_minus1 reader.GetBits(5); // time_offset_length }
// 7.3.2.2 PictureState parameter set RBSP syntax public void Parse(INalUnitReader reader, IResultNodeState resultState) { resultState.Name = Name; uint pictureParameterSetId = reader.GetExpGolombCoded(Attribute.PictureParameterSetId, 255 /*7.4.2.2*/); uint sequenceParameterSetId = reader.GetExpGolombCoded(Attribute.SequenceParameterSetId, 31 /*7.4.2.2*/); var sequenceState = reader.State.SequenceStates[sequenceParameterSetId]; if (sequenceState == null) { resultState.Invalidate(); return; } IPictureStateBuilder builder = new PictureStateBuilder(pictureParameterSetId, sequenceState); builder.EntropyCodingMode = reader.GetBit(Attribute.EntropyCodingMode); builder.BottomFieldPicOrderInFramePresentFlag = reader.GetBit(Attribute.PictureOrderPresent); uint numSliceGroupsMinus1 = reader.GetExpGolombCoded(Attribute.NumSliceGroupsMinus1, 7 /*A.2*/); builder.NumSliceGroupsMinus1 = numSliceGroupsMinus1; if (numSliceGroupsMinus1 > 0) { if (sequenceState.Profile == Profile.Main) { resultState.Invalidate(); return; } ParseSliceGroupMap(reader, resultState, builder, (numSliceGroupsMinus1 + 1)); // FIXME: this code contains too many bugs, so it is disabled for now! resultState.Invalidate(); // (end of FIXME) if (!resultState.Valid) { return; } } builder.NumRefIdxL0DefaultActiveMinus1 = reader.GetExpGolombCoded(Attribute.NumRefIdxl0DefaultActiveMinus1, 31 /*7.4.2.2*/); builder.NumRefIdxL1DefaultActiveMinus1 = reader.GetExpGolombCoded(Attribute.NumRefIdxl1DefaultActiveMinus1, 31 /*7.4.2.2*/); builder.WeightedPredFlag = reader.GetBit(Attribute.WeightedPrediction); builder.WeightedBipredIdc = reader.GetBits(2, Attribute.WeightedBidirectionalPrediction, _weightBidirectionalPredictionFormatter); // SliceQPY = 26 + PicInitQpMinus26 + slice_qp_delta int qpBdOffset = (6 * ((int)sequenceState.BitDepthLuma - 8)); builder.PicInitQpMinus26 = reader.GetSignedExpGolombCoded(Attribute.PictureInitialQPyMinus26, -(26 + qpBdOffset), 25); reader.GetSignedExpGolombCoded(Attribute.PictureInitialQSyMinus26, -26, 25); // pic_init_qs_minus26; relative to 26 reader.GetSignedExpGolombCoded(Attribute.ChromaQpIndexOffset, -12, 12); // chroma_qp_index_offset builder.DeblockingFilterControlPresentFlag = reader.GetBit(Attribute.DeblockingFilterControlPresent); reader.GetBit(Attribute.ConstrainedIntraPrediction); // constrained_intra_pred_flag builder.RedundantPicCntPresentFlag = reader.GetBit(Attribute.RedundantPictureControlPresent); // Note: Total size upto this point is between 11 and 59 bits (+ 'slice group map') if (reader.HasMoreRbspData()) // more_rbsp_data() { builder.Transform8X8ModeFlag = reader.GetBit(); // transform_8x8_mode_flag bool picScalingMatrixPresentFlag = reader.GetBit(); //if (picScalingMatrixPresentFlag) // pic_scaling_matrix_present_flag //{ // for (int i = 0; i < 6 + 2 * pictureState.transform_8x8_mode_flag; i++) // { // bool picScalingListPresentFlag = reader.GetBit(); // if (picScalingListPresentFlag) // pic_scaling_list_present_flag[i] // { // if (i < 6) // { // throw new NotImplementedException("scaling_list(ScalingList4x4[i], 16, UseDefaultScalingMatrix4x4Flag[i]);"); // TODO // } // else // { // throw new NotImplementedException("scaling_list(ScalingList8x8[i – 6], 64, UseDefaultScalingMatrix8x8Flag[i – 6]);"); // TODO // } // } // } //} reader.GetSignedExpGolombCoded(); // second_chroma_qp_index_offset } // rbsp_trailing_bits() if (reader.ShowBits(1) == 1) { reader.GetBit(); // rbsp_stop_one_bit (equal to 1) // trailing zero bits } if (resultState.Valid) { reader.State.PictureStates[pictureParameterSetId] = builder.Build(); } }
private void ResidualBlockCavlc(int startIdx, int endIdx, int maxNumCoeff, CoeffToken coeffToken) { int suffixLength = ((coeffToken.TotalCoeff > 10) && (coeffToken.TrailingOnes < 3)) ? 1 : 0; #if DEBUG H264Debug.Write(" - levels="); if (coeffToken.TrailingOnes > 0) { uint signs = _reader.GetBits(coeffToken.TrailingOnes); // (n) x trailing_ones_sign_flag for (int i = 0; i < coeffToken.TrailingOnes; i++) { H264Debug.Write((((signs & (1 << (coeffToken.TrailingOnes - 1 - i))) == 0) ? "1," : "-1,")); } } #else _reader.GetBits(coeffToken.TrailingOnes); // (n) x trailing_ones_sign_flag #endif for (int i = coeffToken.TrailingOnes; i < coeffToken.TotalCoeff; i++) { int levelCode = GetCoefficientLevelCode(suffixLength); // The first non-zero coefficient after 'trailing ones' must be larger than 1, // unless the maximum count of trailing ones, i.e. 3, was reached. // This will further reduce the amount of bits required to represent a // coefficient level. if ((i == coeffToken.TrailingOnes) && (i /*trailing ones*/ < 3)) { levelCode += 2; // 2 instead of 1, because the lowest bit is the sign bit! } #if DEBUG H264Debug.Write("{0},", ((levelCode % 2) == 0) ? ((levelCode + 2) >> 1) : ((-levelCode - 1) >> 1)); #endif // Automatically adjust the suffix length if high coefficients levels are // encountered, to reduce the number of bits required to represent subsequent // high coefficient levels. if (suffixLength == 0) { suffixLength = 1; } if (suffixLength < 6) { int absLevelMinusOne = (levelCode >> 1); if (absLevelMinusOne >= (3 << (suffixLength - 1))) { suffixLength++; } } } #if DEBUG H264Debug.WriteLine(); #endif if (coeffToken.TotalCoeff < (endIdx - startIdx + 1)) { int zerosLeft = GetTotalZeros(coeffToken.TotalCoeff, maxNumCoeff); // total_zeros #if DEBUG H264Debug.WriteLine(" - total_zeros={0}", zerosLeft); H264Debug.WriteLine("ShowBits(32) = {0:x8} at {1:x8}", _reader.ShowBits(32), _reader.Position); H264Debug.Write(" - run_before="); #endif for (int i = 0; i < (coeffToken.TotalCoeff - 1) && (zerosLeft > 0); i++) { #if DEBUG int runBefore = _reader.GetVlc(RunBeforeTable[Math.Min(zerosLeft, 7)]); zerosLeft -= runBefore; // run_before H264Debug.Write("{0},", runBefore); #else zerosLeft -= _reader.GetVlc(RunBeforeTable[Math.Min(zerosLeft, 7)]); // run_before #endif } #if DEBUG H264Debug.WriteLine(); #endif } }
// 7.3.2.1.1 SequenceState parameter set data syntax public void Parse(INalUnitReader reader, IResultNodeState resultState) { // Constraints from 7.4.2.11 resultState.Name = Name; Profile profileIdc = reader.GetBits(8, Attribute.ProfileIdc, _profileValidator); reader.GetBits(6); // constraint_set{0-5}_flag if (reader.GetBits(2) != 0) // reserved_zero_2bits { resultState.Invalidate(); return; } reader.GetByte(false, Attribute.LevelIdc, 59); // level_idc, Table A-1 - Level limits uint sequenceParameterSetId = reader.GetExpGolombCoded(Attribute.SequenceParameterSetId, 31); ISequenceStateBuilder builder = new SequenceStateBuilder(sequenceParameterSetId); builder.ByteStreamFormat = reader.State.ByteStreamFormat; builder.ProfileIdc = profileIdc; if (IsHighProfile(profileIdc)) { uint chromaFormatIdc = reader.GetExpGolombCoded(Attribute.ChromaFormatIdc, 3); // Table 6-1 builder.ChromaFormatIdc = chromaFormatIdc; if (chromaFormatIdc == 3) { builder.SeparateColourPlaneFlag = reader.GetBit(Attribute.SeparateColorPlaneFlag); } builder.BitDepthLumaMinus8 = reader.GetExpGolombCoded(Attribute.BitDepthLumaArraySampleMinus8, 6); builder.BitDepthChromaMinus8 = reader.GetExpGolombCoded(Attribute.BitDepthChromaArraySampleMinus8, 6); reader.GetBit(); // qpprime_y_zero_transform_bypass_flag if (reader.GetBit()) // seq_scaling_matrix_present_flag { for (int i = 0; i < ((chromaFormatIdc != 3) ? 8 : 12); i++) { if (reader.GetBit()) // seq_scaling_list_present_flag[i] { // FIXME: scaling_list() is not implemented!! resultState.Invalidate(); return; } } } } builder.Log2MaxFrameNumMinus4 = reader.GetExpGolombCoded(Attribute.Log2MaxFrameNumMinus4, 28); DecodePictureOrderCount(reader, builder); uint maxDpbFramesUpperLimit = (profileIdc == Profile.MultiviewHigh) ? 160U : 16U; //could use the exact maxDpbFrames, but this is easier builder.MaxNumRefFrames = reader.GetExpGolombCoded(Attribute.MaxNumberReferenceFrames, maxDpbFramesUpperLimit); reader.GetBit(); // gaps_in_frame_num_value_allowed_flag builder.PicWidthInMbsMinus1 = reader.GetExpGolombCoded(Attribute.PictureWidthInMacroBlocksMinus1, 543); builder.PicHeightInMapUnitsMinus1 = reader.GetExpGolombCoded(Attribute.PictureHeightInMapUnitsMinus1, 543); var frameMbsOnlyFlag = reader.GetBit(Attribute.FrameMbsOnlyFlag); builder.FrameMbsOnlyFlag = frameMbsOnlyFlag; if (!frameMbsOnlyFlag) { builder.MbAdaptiveFrameFieldFlag = reader.GetBit(); } bool direct8X8InferenceFlag = reader.GetBit(); builder.Direct8X8InferenceFlag = direct8X8InferenceFlag; if (!frameMbsOnlyFlag && !direct8X8InferenceFlag) { resultState.Invalidate(); return; } if (reader.GetBit()) // frame_cropping_flag { // TODO: Cropping should not exceed the size of a frame! reader.GetExpGolombCoded(Attribute.FrameCropLeftOffset, 8703); reader.GetExpGolombCoded(Attribute.FrameCropRightOffset, 8703); reader.GetExpGolombCoded(Attribute.FrameCropTopOffset, 8703); reader.GetExpGolombCoded(Attribute.FrameCropBottomOffset, 8703); } if (reader.GetBit()) // vui_parameters_present_flag { GetVuiParameters(reader, resultState); } if (reader.ShowBits(1) == 1) { reader.GetBit(); // rbsp_stop_one_bit (equal to 1) // trailing zero bits } if (resultState.Valid) { reader.State.SequenceStates[sequenceParameterSetId] = builder.Build(); } }
private static void GetVuiParameters(INalUnitReader reader, IResultNodeState resultState) { const byte extendedSar = 255; // Extended_SAR bool aspectRatioInfoPresentFlag = reader.GetBit(); if (aspectRatioInfoPresentFlag) // aspect_ratio_info_present_flag { byte aspectRatioIdc = reader.GetByte(false); if (aspectRatioIdc == extendedSar) // aspect_ratio_idc { reader.GetBits(16); // sar_width reader.GetBits(16); // sar_height } } bool overscanInfoPresentFlag = reader.GetBit(); if (overscanInfoPresentFlag) // overscan_info_present_flag { reader.GetBit(); // overscan_appropriate_flag } bool videoSignalTypePresentFlag = reader.GetBit(); if (videoSignalTypePresentFlag) // video_signal_type_present_flag { reader.GetBits(3); // video_format reader.GetBit(); // video_full_range_flag bool colourDescriptionPresentFlag = reader.GetBit(); if (colourDescriptionPresentFlag) // colour_description_present_flag { reader.GetByte(false); // colour_primaries reader.GetByte(false); // transfer_characteristics reader.GetByte(false); // matrix_coefficients } } bool chromaLocInfoPresentFlag = reader.GetBit(); if (chromaLocInfoPresentFlag) // chroma_loc_info_present_flag { reader.GetExpGolombCoded(); // chroma_sample_loc_type_top_field reader.GetExpGolombCoded(); // chroma_sample_loc_type_bottom_field } bool timingInfoPresentFlag = reader.GetBit(); if (timingInfoPresentFlag) // timing_info_present_flag { reader.GetBits(32); // num_units_in_tick reader.GetBits(32); // time_scale reader.GetBit(); // fixed_frame_rate_flag } bool nalHrdParametersPresentFlag = reader.GetBit(); if (nalHrdParametersPresentFlag) //nal_hrd_parameters_present_flag { GetHrdParameters(reader, resultState); // hrd_parameters() } bool vclHrdParametersPresentFlag = reader.GetBit(); if (vclHrdParametersPresentFlag) // vcl_hrd_parameters_present_flag { GetHrdParameters(reader, resultState); // hrd_parameters() } if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) { reader.GetBit(); // low_delay_hrd_flag } reader.GetBit(); // pic_struct_present_flag bool bitstreamRestrictionFlag = reader.GetBit(); if (bitstreamRestrictionFlag) // bitstream_restriction_flag { reader.GetBit(); // motion_vectors_over_pic_boundaries_flag reader.GetExpGolombCoded(); // max_bytes_per_pic_denom reader.GetExpGolombCoded(); // max_bits_per_mb_denom reader.GetExpGolombCoded(); // log2_max_mv_length_horizontal reader.GetExpGolombCoded(); // log2_max_mv_length_vertical reader.GetExpGolombCoded(); // num_reorder_frames reader.GetExpGolombCoded(); // max_dec_frame_buffering } }