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; } }
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 bool GetCodedBlockFlag(uint ctxBlockCat, ref CodedBlockFlags codedBlockFlags, uint subBlkIdx) { uint ctxIdx = CodedBlockFlagCtxBlockCatOffset[ctxBlockCat] + codedBlockFlags.GetCtxIdxInc(subBlkIdx); return(_arithmeticDecoder.DecodeDecision(ctxIdx) == 1); }