private void ResidualLuma(IMacroblockType macroBlockType, int startIdx, int endIdx, ref CodedBlockFlags codedBlockFlags, int comp) { if ((startIdx == 0) && macroBlockType.IsIntra16X16) { if (GetCodedBlockFlag(CtxBlockCatTabLuma[comp, 0], ref codedBlockFlags, 32)) { codedBlockFlags.SetCodedBlockFlag(32); ResidualBlockCabac(0, 15, 16, CtxBlockCatTabLuma[comp, 0]); } } for (uint i8X8 = 0; i8X8 < 4; i8X8++) { if (_codedBlockPattern.IsLumaBitSet(i8X8)) { if (_mbFlags.TransformSize8X8Flag) { if ((ChromaFormat != ChromaFormat.YCbCr444) || GetCodedBlockFlag(CtxBlockCatTabLuma[comp, 3], ref codedBlockFlags, i8X8 + 16)) { ResidualBlockCabac((4 * startIdx), (4 * endIdx) + 3, 64, CtxBlockCatTabLuma[comp, 3]); // Update coded_block_flag prediction codedBlockFlags.SetCodedBlockFlag(i8X8 + 16); } } else { for (uint i4X4 = 0; i4X4 < 4; i4X4++) { uint ctxBlockCat = macroBlockType.IsIntra16X16 ? CtxBlockCatTabLuma[comp, 1] : CtxBlockCatTabLuma[comp, 2]; uint subBlkIdx = ((i8X8 << 2) + i4X4); if (GetCodedBlockFlag(ctxBlockCat, ref codedBlockFlags, subBlkIdx)) { codedBlockFlags.SetCodedBlockFlag(subBlkIdx); if (macroBlockType.IsIntra16X16) { ResidualBlockCabac(Math.Max(0, (startIdx - 1)), (endIdx - 1), 15, ctxBlockCat); } else { ResidualBlockCabac(startIdx, endIdx, 16, ctxBlockCat); } } } } } } }
private void ResidualLuma(IMacroblockType macroBlockType, int startIdx, int endIdx, CodedCoefficients codedCoefficients) { if ((startIdx == 0) && macroBlockType.IsIntra16X16) { var coeffTokenDc = GetCoeffToken(codedCoefficients, 0); #if DEBUG H264Debug.WriteLine(" coeff_token( luma dc )={0}", coeffTokenDc); #endif if (coeffTokenDc.TotalCoeff != 0) { ResidualBlockCavlc(0, 15, 16, coeffTokenDc); } } for (uint i8X8 = 0; i8X8 < 4; i8X8++) { if (IsLumaBitSet(i8X8)) { for (uint i4X4 = 0; i4X4 < 4; i4X4++) { uint subBlkIdx = ((i8X8 << 2) + i4X4); var coeffToken = GetCoeffToken(codedCoefficients, subBlkIdx); #if DEBUG H264Debug.WriteLine(" coeff_token={0}", coeffToken); #endif if (coeffToken.TotalCoeff != 0) { if (macroBlockType.IsIntra16X16) { ResidualBlockCavlc(Math.Max(0, (startIdx - 1)), (endIdx - 1), 15, coeffToken); } else { ResidualBlockCavlc(startIdx, endIdx, 16, coeffToken); } } } } else { // Clear non-zero coefficient predictions for non-coded blocks for (uint i4X4 = 0; i4X4 < 4; i4X4++) { codedCoefficients.UpdateTotalCoeff((int)_currMbAddr, (4 * i8X8) + i4X4, 0); } } } }
private void Residual(IMacroblockType macroBlockType, int startIdx, int endIdx) { ResidualLuma(macroBlockType, startIdx, endIdx, _lumaCodedCoefficients); if (_sequenceState.IsChromaSubsampling) // Chroma format 4:2:0 or 4:2:2 { uint numSubBlocks = (4 * ChromaFormat.NumC8X8); // in 4x4 blocks if (IsChromaDcResidualPresent() && (startIdx == 0)) { for (uint iCbCr = 0; iCbCr < 2; iCbCr++) { var coeffToken = GetChromaCoeffToken(); if (coeffToken.TotalCoeff != 0) { ResidualBlockCavlc(0, (int)(numSubBlocks - 1), (int)numSubBlocks, coeffToken); } } } if (IsChromaAcResidualPresent()) { for (uint iCbCr = 0; iCbCr < 2; iCbCr++) { CodedCoefficients codedCoefficients = _chromaCodedCoefficients[iCbCr]; for (uint i = 0; i < numSubBlocks; i++) { var coeffToken = GetCoeffToken(codedCoefficients, i); if (coeffToken.TotalCoeff != 0) { ResidualBlockCavlc(Math.Max(0, (startIdx - 1)), (endIdx - 1), 15, coeffToken); } } } } else { // Clear non-zero coefficient predictions for non-coded blocks _chromaCodedCoefficients[Cb].UpdateTotalCoeff((int)_currMbAddr, 0); _chromaCodedCoefficients[Cr].UpdateTotalCoeff((int)_currMbAddr, 0); } } else if (ChromaFormat == ChromaFormat.YCbCr444) { ResidualLuma(macroBlockType, startIdx, endIdx, _chromaCodedCoefficients[0]); // Cb ResidualLuma(macroBlockType, startIdx, endIdx, _chromaCodedCoefficients[1]); // Cr } }
private void Residual(IMacroblockType macroBlockType, int startIdx, int endIdx) { // Special case for unavailable macroblock states of intra coded blocks in inter-coded slices bool b1 = macroBlockType.IntraCoded && !_sliceState.IntraCoded; bool b2 = _mbFlags.TransformSize8X8Flag && (ChromaFormat == ChromaFormat.YCbCr444); if (b1 || b2) { byte unavailableCodedBlockFlags = (byte)(macroBlockType.IntraCoded ? 0xff : 0); if ((b1 && ((_mbStateA.Flags & 0x40) == 0x40)) || (b2 && ((_mbStateA.Flags & 0x4) == 0))) { _mbStateA.LumaCodedBlockFlags = unavailableCodedBlockFlags; _mbStateA.CrCodedBlockFlags = unavailableCodedBlockFlags; _mbStateA.CbCodedBlockFlags = unavailableCodedBlockFlags; } if ((b1 && ((_mbStateB.Flags & 0x40) == 0x40)) || (b2 && ((_mbStateB.Flags & 0x4) == 0))) { _mbStateB.LumaCodedBlockFlags = unavailableCodedBlockFlags; _mbStateB.CrCodedBlockFlags = unavailableCodedBlockFlags; _mbStateB.CbCodedBlockFlags = unavailableCodedBlockFlags; } } var codedBlockFlags = new CodedBlockFlags(_mbStateA.LumaCodedBlockFlags, _mbStateB.LumaCodedBlockFlags); ResidualLuma(macroBlockType, startIdx, endIdx, ref codedBlockFlags, 0); _currMbState.LumaCodedBlockFlags = codedBlockFlags.Flags; if (_sequenceState.IsChromaSubsampling) // Chroma format 4:2:0 or 4:2:2 { if (_codedBlockPattern.IsChromaDcResidualPresent) { // ReSharper disable SuggestUseVarKeywordEvident int numSubBlocks = (int)(4 * ChromaFormat.NumC8X8); // in 4x4 blocks // ReSharper restore SuggestUseVarKeywordEvident var cbCodedBlockFlags = new CodedBlockFlags(_mbStateA.CbCodedBlockFlags, _mbStateB.CbCodedBlockFlags); var crCodedBlockFlags = new CodedBlockFlags(_mbStateA.CrCodedBlockFlags, _mbStateB.CrCodedBlockFlags); if (GetCodedBlockFlag(3, ref cbCodedBlockFlags, 32)) { cbCodedBlockFlags.SetCodedBlockFlag(32); ResidualBlockCabac(0, (numSubBlocks - 1), numSubBlocks, 3); } if (GetCodedBlockFlag(3, ref crCodedBlockFlags, 32)) { crCodedBlockFlags.SetCodedBlockFlag(32); ResidualBlockCabac(0, (numSubBlocks - 1), numSubBlocks, 3); } if (_codedBlockPattern.IsChromaAcResidualPresent) { uint cbfIndex = 16U + (uint)numSubBlocks; for (uint i = 0; i < numSubBlocks; i++) { if (GetCodedBlockFlag(4, ref cbCodedBlockFlags, cbfIndex + i)) { cbCodedBlockFlags.SetCodedBlockFlag(cbfIndex + i); ResidualBlockCabac(Math.Max(0, (startIdx - 1)), (endIdx - 1), 15, 4); } } for (uint i = 0; i < numSubBlocks; i++) { if (GetCodedBlockFlag(4, ref crCodedBlockFlags, cbfIndex + i)) { crCodedBlockFlags.SetCodedBlockFlag(cbfIndex + i); ResidualBlockCabac(Math.Max(0, (startIdx - 1)), (endIdx - 1), 15, 4); } } } _currMbState.CbCodedBlockFlags = cbCodedBlockFlags.Flags; _currMbState.CrCodedBlockFlags = crCodedBlockFlags.Flags; } } else if (ChromaFormat == ChromaFormat.YCbCr444) { #if DEBUG H264Debug.WriteLine(" [Cb]"); #endif var cbCodedBlockFlags = new CodedBlockFlags(_mbStateA.CbCodedBlockFlags, _mbStateB.CbCodedBlockFlags); ResidualLuma(macroBlockType, startIdx, endIdx, ref cbCodedBlockFlags, 1); _currMbState.CbCodedBlockFlags = cbCodedBlockFlags.Flags; #if DEBUG H264Debug.WriteLine(" [Cr]"); #endif var crCodedBlockFlags = new CodedBlockFlags(_mbStateA.CrCodedBlockFlags, _mbStateB.CrCodedBlockFlags); ResidualLuma(macroBlockType, startIdx, endIdx, ref crCodedBlockFlags, 2); // Cr _currMbState.CrCodedBlockFlags = crCodedBlockFlags.Flags; } }
// 7.3.5.1 Macroblock prediction syntax private void MacroBlockPrediction(IMacroblockType macroBlockType) { if (macroBlockType.IsIntra4X4 || macroBlockType.IsIntra16X16) { if (macroBlockType.IsIntra4X4) { int lumaSubBlocks = _mbFlags.TransformSize8X8Flag ? 4 : 16; for (int i = 0; i < lumaSubBlocks; i++) { if (GetPrevIntra4X4PredModeFlag() == 0) // prev_intra4x4_pred_mode_flag[luma4x4BlkIdx]) { GetRemIntra4X4PredMode(); // rem_intra4x4_pred_mode[luma4x4BlkIdx] } } } if (_sequenceState.IsChromaSubsampling) { GetIntraChromaPredMode(); // intra_chroma_pred_mode } } else if (!macroBlockType.IsDirect) { uint numMbPart = macroBlockType.NumMbPart; // either 1 or 2 MacroblockPartitioning macroblockPartitioning = macroBlockType.MacroblockPartitioning; uint referencePictureCount0 = _sliceState.ActiveReferencePictureCount0; //defaults to _pictureState.DefaultReferencePictureCount0; if (HasReferencePictureIndex(referencePictureCount0)) { var referencePictureIndex = new ReferencePictureIndex(_mbStateA.RefIdxL0, _mbStateB.RefIdxL0); for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList0Predicted(i)) { uint idx = macroblockPartitioning[i].Idx; if (GetReferencePicture(referencePictureCount0, referencePictureIndex.GetCtxIdxInc(idx))) // ref_idx_l0[ mbPartIdx ] { referencePictureIndex.SetNonZeroRefIdx(idx); } } } _currMbState.RefIdxL0 = referencePictureIndex.Bits; } uint referencePictureCount1 = _sliceState.ActiveReferencePictureCount1; //defaults to _pictureState.DefaultReferencePictureCount1; if (HasReferencePictureIndex(referencePictureCount1)) { var referencePictureIndex = new ReferencePictureIndex(_mbStateA.RefIdxL1, _mbStateB.RefIdxL1); for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList1Predicted(i)) { uint idx = macroblockPartitioning[i].Idx; if (GetReferencePicture(referencePictureCount1, referencePictureIndex.GetCtxIdxInc(idx))) // ref_idx_l1[ mbPartIdx ] { referencePictureIndex.SetNonZeroRefIdx(idx); } } } _currMbState.RefIdxL1 = referencePictureIndex.Bits; } for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList0Predicted(i)) { GetMotionVector(_motionFieldL0, macroblockPartitioning[i]); // mvd_l0[ i ][ 0 ][ compIdx ] } } for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList1Predicted(i)) { GetMotionVector(_motionFieldL1, macroblockPartitioning[i]); // mvd_l1[ i ][ 0 ][ compIdx ] } } } }
private void MacroBlockLayer() { IMacroblockType macroBlockType = GetMacroblockType(); #if DEBUG H264Debug.WriteLine("{0}: mb_type={1}", CurrentMbIndex, macroBlockType); #endif if (macroBlockType.IsIPcm) { _reader.GetPcmSamples(); InitializeCabac(); _currMbState = MacroblockState.Pcm; } else { bool transform8X8ModeFlagSet = false; if (macroBlockType.NumMbPart == 4) { // Note: Only inter-coded blocks can have mb parts, in particular, // we are not currently decoding an intra-coded block! SubMacroBlockPrediction(); if (HasSubMbPartSizeLessThan8X8()) { transform8X8ModeFlagSet = true; // Transform 8x8 mode is not possible! } } else { if (_pictureState.Transform8X8ModeFlag && macroBlockType.IsI_NxN) { GetTransformSize8X8Flag(); transform8X8ModeFlagSet = true; } MacroBlockPrediction(macroBlockType); } if (macroBlockType.IsIntra16X16) { _codedBlockPattern = new CodedBlockPattern(macroBlockType.CodedBlockPattern); } else { GetCodedBlockPattern(); if (_pictureState.Transform8X8ModeFlag && !transform8X8ModeFlagSet && _codedBlockPattern.IsLumaResidualPresent && (!macroBlockType.IsDirect || _sequenceState.Direct8X8InferenceFlag)) { GetTransformSize8X8Flag(); } } _currMbState.CodedBlockPattern = _codedBlockPattern.Bits; if (_codedBlockPattern.IsResidualPresent || macroBlockType.IsIntra16X16) { GetMbQpDelta(); // mb_qp_delta Residual(macroBlockType, 0, 15); } } }
private void SubMacroBlockPrediction(IMacroblockType macroBlockType) { if (_sliceState.SliceType == SliceType.B) { for (uint mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) { uint subMbType = _reader.GetExpGolombCoded(12); // sub_mb_type[mbPartIdx] _subMbTypes[mbPartIdx] = SubMacroblockType.GetSubMbTypeB(subMbType); } } else // P or Sp { for (uint mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) { uint subMbType = _reader.GetExpGolombCoded(3); // sub_mb_type[mbPartIdx] _subMbTypes[mbPartIdx] = SubMacroblockType.GetSubMbTypeP(subMbType); } } uint referencePictureCount0 = _sliceState.ActiveReferencePictureCount0; //defaults to _pictureState.DefaultReferencePictureCount0; if (HasReferencePictureIndex(referencePictureCount0) && !macroBlockType.IsP8X8Ref0) { for (uint mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) { if (_subMbTypes[mbPartIdx].List0Predicted) { GetReferencePicture(referencePictureCount0); } } } uint referencePictureCount1 = _sliceState.ActiveReferencePictureCount1; //defaults to _pictureState.DefaultReferencePictureCount1; if (HasReferencePictureIndex(referencePictureCount1)) { for (uint mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) { if (_subMbTypes[mbPartIdx].List1Predicted) { GetReferencePicture(referencePictureCount1); } } } for (uint mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) { ISubMacroblockType subMbType = _subMbTypes[mbPartIdx]; if (subMbType.List0Predicted) { for (uint subMbPartIdx = 0; subMbPartIdx < subMbType.NumSubMbPart; subMbPartIdx++) { GetMotionVector(); // mvd_l0[ i ][ j ][ compIdx ] } } } for (uint mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) { ISubMacroblockType subMbType = _subMbTypes[mbPartIdx]; if (subMbType.List1Predicted) { for (uint subMbPartIdx = 0; subMbPartIdx < subMbType.NumSubMbPart; subMbPartIdx++) { GetMotionVector(); // mvd_l1[ i ][ j ][ compIdx ] } } } }
// 7.3.5.1 Macroblock prediction syntax private void MacroBlockPrediction(IMacroblockType macroBlockType, bool transformSize8X8Flag) { if (macroBlockType.IsIntra4X4 || macroBlockType.IsIntra16X16) { if (macroBlockType.IsIntra4X4) { uint lumaSubBlocks = transformSize8X8Flag ? 4U : 16U; for (uint i = 0; i < lumaSubBlocks; i++) { if (!_reader.GetBit()) // prev_intra4x4_pred_mode_flag[luma4x4BlkIdx]) { _reader.GetBits(3); // rem_intra4x4_pred_mode[luma4x4BlkIdx] } } } if (_sequenceState.IsChromaSubsampling) { _reader.GetExpGolombCoded(); // intra_chroma_pred_mode } } else if (!macroBlockType.IsDirect) { uint numMbPart = macroBlockType.NumMbPart; // either 1 or 2 uint referencePictureCount0 = _sliceState.ActiveReferencePictureCount0; //defaults to _pictureState.DefaultReferencePictureCount0; if (HasReferencePictureIndex(referencePictureCount0)) { for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList0Predicted(i)) { GetReferencePicture(referencePictureCount0); // ref_idx_l0[ mbPartIdx ] } } } uint referencePictureCount1 = _sliceState.ActiveReferencePictureCount1; //defaults to _pictureState.DefaultReferencePictureCount1; if (HasReferencePictureIndex(referencePictureCount1)) { for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList1Predicted(i)) { GetReferencePicture(referencePictureCount1); // ref_idx_l1[ mbPartIdx ] } } } for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList0Predicted(i)) { GetMotionVector(); // mvd_l0[ i ][ 0 ][ compIdx ] } } for (uint i = 0; i < numMbPart; i++) { if (macroBlockType.IsList1Predicted(i)) { GetMotionVector(); // mvd_l1[ i ][ 0 ][ compIdx ] } } } }
private void MacroBlockLayer() { //page 76 IMacroblockType macroBlockType = GetMacroBlockType(); #if DEBUG H264Debug.WriteLine("{0}: mb_type={1}", CurrentMbIndex, macroBlockType); H264Debug.WriteLine("ShowBits(32) = {0:x8} at {1:x8}", _reader.ShowBits(32), _reader.Position); #endif if (macroBlockType.IsIPcm) { _reader.GetPcmSamples(); _lumaCodedCoefficients.UpdateTotalCoeff((int)_currMbAddr, 16); _chromaCodedCoefficients[Cb].UpdateTotalCoeff((int)_currMbAddr, 16); _chromaCodedCoefficients[Cr].UpdateTotalCoeff((int)_currMbAddr, 16); } else { bool transform8X8ModeFlagSet = false; if (macroBlockType.NumMbPart == 4) { // Note: Only inter-coded blocks can have mb parts, in particular, // we are not currently decoding an intra-coded block! SubMacroBlockPrediction(macroBlockType); if (HasSubMbPartSizeLessThan8X8()) { transform8X8ModeFlagSet = true; // Transform 8x8 mode is not possible! } } else { bool transformSize8X8Flag = false; if (_pictureState.Transform8X8ModeFlag && macroBlockType.IsI_NxN) { transformSize8X8Flag = _reader.GetBit(); transform8X8ModeFlagSet = true; } MacroBlockPrediction(macroBlockType, transformSize8X8Flag); } if (macroBlockType.IsIntra16X16) { _codedBlockPattern = macroBlockType.CodedBlockPattern; } else { GetCodedBlockPattern(macroBlockType.IntraCoded); if (_pictureState.Transform8X8ModeFlag && !transform8X8ModeFlagSet && ((_codedBlockPattern & 15) /*luma*/ != 0) && (!macroBlockType.IsDirect || _sequenceState.Direct8X8InferenceFlag)) { _reader.GetBit(); // transform_size_8x8_flag } } if ((_codedBlockPattern != 0) || macroBlockType.IsIntra16X16) { _reader.GetSignedExpGolombCoded(_sequenceState.MinMbQpDelta, _sequenceState.MaxMbQpDelta); // mb_qp_delta Residual(macroBlockType, 0, 15); } else { UpdateSkippedMacroblockPrediction(); } } }