private void GetMotionVector(MotionField motionField, MacroblockPartition mbPart) { #if DEBUG int dmvx = 0, dmvy = 0; #endif if (_arithmeticDecoder.DecodeDecision(40 + motionField.GetCtxIdxInc(_currMbAddr, mbPart, 0)) == 1) { uint dx = GetAbsMotionVectorComponent(40); // dx coordinate? motionField.UpdateComponent(_currMbAddr, mbPart, 0, dx); #if DEBUG dmvx = (_arithmeticDecoder.DecodeBypass() == 1) ? -(int)dx : (int)dx; // sign? #else _arithmeticDecoder.DecodeBypass(); // sign #endif } if (_arithmeticDecoder.DecodeDecision(47 + motionField.GetCtxIdxInc(_currMbAddr, mbPart, 1)) == 1) { uint dy = GetAbsMotionVectorComponent(47); // dy coordinate? motionField.UpdateComponent(_currMbAddr, mbPart, 1, dy); #if DEBUG dmvy = (_arithmeticDecoder.DecodeBypass() == 1) ? -(int)dy : (int)dy; // sign? #else _arithmeticDecoder.DecodeBypass(); // sign #endif } #if DEBUG H264Debug.WriteLine(" dmv={0},{1}", dmvx, dmvy); #endif }
internal int PredictTotalCoeff(uint mbIndex, uint subBlockIndex) { int nTop = GetTopNumberCoeff(mbIndex, subBlockIndex); int nLeft = GetLeftNumberCoeff(mbIndex, subBlockIndex); #if DEBUG H264Debug.WriteLine(" * (left={0}, top={1}, nzc={2})", nLeft, nTop, TotalCoeffLookup[nLeft + nTop]); #endif return(TotalCoeffLookup[nLeft + nTop]); }
private void GetMotionVector() { #if DEBUG int dx = _reader.GetSignedExpGolombCoded(); // dx coordinate? int dy = _reader.GetSignedExpGolombCoded(); // dy coordinate? H264Debug.WriteLine(" dmv={0},{1}", dx, dy); #else _reader.GetSignedExpGolombCoded(); // dmv(x) _reader.GetSignedExpGolombCoded(); // dmv(y) #endif }
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) { // 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 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); } } }
public void Parse() { InitializeCabac(); _currMbAddr = _sliceState.FirstMacroBlockInSlice * (MbAffFrameFlag ? 2U : 1U); MbFieldDecodingFlag = _sliceState.FieldPicFlag; // The default for non-MBAFF frames bool moreDataFlag = true; bool prevMbSkipped = false; while (_readerState.Valid && moreDataFlag) { _currMbState = new MacroblockState(); _mbQpDeltaNotZero = 0; // Load macroblock states for block A (left) and B (top) _mbStateA = GetMacroblockState(_sliceState.GetMbAddrA(_currMbAddr)); _mbStateB = GetMacroblockState(_sliceState.GetMbAddrB(_currMbAddr)); _mbFlags = new MacroblockFlags(_mbStateA.Flags, _mbStateB.Flags); bool mbSkipFlag = false; if (!_sliceState.IntraCoded) { mbSkipFlag = GetMbSkipFlag(); // mb_skip_flag } if (!mbSkipFlag) { _mbFlags.SetCodedBlockFlag(); if (MbAffFrameFlag && (IsFirstMacroblockInPair() || prevMbSkipped)) { MbFieldDecodingFlag = GetMbFieldDecodingFlag(); // is field macro block } MacroBlockLayer(); } if (MbFieldDecodingFlag && (!MbAffFrameFlag || IsLastMacroblockInPair())) { _mbFlags.SetFieldDecodingMode(); } _currMbState.Flags = _mbFlags.Bits; _macroblockStates[_currMbAddr] = _currMbState; _prevMbQpDeltaNotZero = _mbQpDeltaNotZero; if (!_sliceState.IntraCoded) { prevMbSkipped = mbSkipFlag; } if (!MbAffFrameFlag || IsLastMacroblockInPair()) { moreDataFlag = !GetEndOfSliceFlag(); } if (moreDataFlag) { NextMbAddress(); } } #if DEBUG H264Debug.WriteLine(" - Terminated ({4}) at {0} of {1} ({2}), nextBits(16)={3}", _reader.Position, _reader.Length, _currMbAddr, ToBitString(_reader.ShowBits(16), 16), _sliceState.SliceType.ToString()); #endif }
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 } }
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(); } } }