diff options
Diffstat (limited to 'Ryujinx.Graphics.Nvdec/VDec/H264Decoder.cs')
| -rw-r--r-- | Ryujinx.Graphics.Nvdec/VDec/H264Decoder.cs | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Nvdec/VDec/H264Decoder.cs b/Ryujinx.Graphics.Nvdec/VDec/H264Decoder.cs new file mode 100644 index 00000000..24c7e0b9 --- /dev/null +++ b/Ryujinx.Graphics.Nvdec/VDec/H264Decoder.cs @@ -0,0 +1,238 @@ +using System.IO; + +namespace Ryujinx.Graphics.VDec +{ + class H264Decoder + { + private int _log2MaxPicOrderCntLsbMinus4; + private bool _deltaPicOrderAlwaysZeroFlag; + private bool _frameMbsOnlyFlag; + private int _picWidthInMbs; + private int _picHeightInMapUnits; + private bool _entropyCodingModeFlag; + private bool _bottomFieldPicOrderInFramePresentFlag; + private int _numRefIdxL0DefaultActiveMinus1; + private int _numRefIdxL1DefaultActiveMinus1; + private bool _deblockingFilterControlPresentFlag; + private bool _redundantPicCntPresentFlag; + private bool _transform8x8ModeFlag; + private bool _mbAdaptiveFrameFieldFlag; + private bool _direct8x8InferenceFlag; + private bool _weightedPredFlag; + private bool _constrainedIntraPredFlag; + private bool _fieldPicFlag; + private bool _bottomFieldFlag; + private int _log2MaxFrameNumMinus4; + private int _chromaFormatIdc; + private int _picOrderCntType; + private int _picInitQpMinus26; + private int _chromaQpIndexOffset; + private int _chromaQpIndexOffset2; + private int _weightedBipredIdc; + private int _frameNumber; + private byte[] _scalingMatrix4; + private byte[] _scalingMatrix8; + + public void Decode(H264ParameterSets Params, H264Matrices matrices, byte[] frameData) + { + _log2MaxPicOrderCntLsbMinus4 = Params.Log2MaxPicOrderCntLsbMinus4; + _deltaPicOrderAlwaysZeroFlag = Params.DeltaPicOrderAlwaysZeroFlag; + _frameMbsOnlyFlag = Params.FrameMbsOnlyFlag; + _picWidthInMbs = Params.PicWidthInMbs; + _picHeightInMapUnits = Params.PicHeightInMapUnits; + _entropyCodingModeFlag = Params.EntropyCodingModeFlag; + _bottomFieldPicOrderInFramePresentFlag = Params.BottomFieldPicOrderInFramePresentFlag; + _numRefIdxL0DefaultActiveMinus1 = Params.NumRefIdxL0DefaultActiveMinus1; + _numRefIdxL1DefaultActiveMinus1 = Params.NumRefIdxL1DefaultActiveMinus1; + _deblockingFilterControlPresentFlag = Params.DeblockingFilterControlPresentFlag; + _redundantPicCntPresentFlag = Params.RedundantPicCntPresentFlag; + _transform8x8ModeFlag = Params.Transform8x8ModeFlag; + + _mbAdaptiveFrameFieldFlag = ((Params.Flags >> 0) & 1) != 0; + _direct8x8InferenceFlag = ((Params.Flags >> 1) & 1) != 0; + _weightedPredFlag = ((Params.Flags >> 2) & 1) != 0; + _constrainedIntraPredFlag = ((Params.Flags >> 3) & 1) != 0; + _fieldPicFlag = ((Params.Flags >> 5) & 1) != 0; + _bottomFieldFlag = ((Params.Flags >> 6) & 1) != 0; + + _log2MaxFrameNumMinus4 = (int)(Params.Flags >> 8) & 0xf; + _chromaFormatIdc = (int)(Params.Flags >> 12) & 0x3; + _picOrderCntType = (int)(Params.Flags >> 14) & 0x3; + _picInitQpMinus26 = (int)(Params.Flags >> 16) & 0x3f; + _chromaQpIndexOffset = (int)(Params.Flags >> 22) & 0x1f; + _chromaQpIndexOffset2 = (int)(Params.Flags >> 27) & 0x1f; + _weightedBipredIdc = (int)(Params.Flags >> 32) & 0x3; + _frameNumber = (int)(Params.Flags >> 46) & 0x1ffff; + + _picInitQpMinus26 = (_picInitQpMinus26 << 26) >> 26; + _chromaQpIndexOffset = (_chromaQpIndexOffset << 27) >> 27; + _chromaQpIndexOffset2 = (_chromaQpIndexOffset2 << 27) >> 27; + + _scalingMatrix4 = matrices.ScalingMatrix4; + _scalingMatrix8 = matrices.ScalingMatrix8; + + if (FFmpegWrapper.IsInitialized) + { + FFmpegWrapper.DecodeFrame(frameData); + } + else + { + FFmpegWrapper.H264Initialize(); + + FFmpegWrapper.DecodeFrame(DecoderHelper.Combine(EncodeHeader(), frameData)); + } + } + + private byte[] EncodeHeader() + { + using (MemoryStream data = new MemoryStream()) + { + H264BitStreamWriter writer = new H264BitStreamWriter(data); + + // Sequence Parameter Set. + writer.WriteU(1, 24); + writer.WriteU(0, 1); + writer.WriteU(3, 2); + writer.WriteU(7, 5); + writer.WriteU(100, 8); + writer.WriteU(0, 8); + writer.WriteU(31, 8); + writer.WriteUe(0); + writer.WriteUe(_chromaFormatIdc); + + if (_chromaFormatIdc == 3) + { + writer.WriteBit(false); + } + + writer.WriteUe(0); + writer.WriteUe(0); + writer.WriteBit(false); + writer.WriteBit(false); //Scaling matrix present flag + + writer.WriteUe(_log2MaxFrameNumMinus4); + writer.WriteUe(_picOrderCntType); + + if (_picOrderCntType == 0) + { + writer.WriteUe(_log2MaxPicOrderCntLsbMinus4); + } + else if (_picOrderCntType == 1) + { + writer.WriteBit(_deltaPicOrderAlwaysZeroFlag); + + writer.WriteSe(0); + writer.WriteSe(0); + writer.WriteUe(0); + } + + int picHeightInMbs = _picHeightInMapUnits / (_frameMbsOnlyFlag ? 1 : 2); + + writer.WriteUe(16); + writer.WriteBit(false); + writer.WriteUe(_picWidthInMbs - 1); + writer.WriteUe(picHeightInMbs - 1); + writer.WriteBit(_frameMbsOnlyFlag); + + if (!_frameMbsOnlyFlag) + { + writer.WriteBit(_mbAdaptiveFrameFieldFlag); + } + + writer.WriteBit(_direct8x8InferenceFlag); + writer.WriteBit(false); //Frame cropping flag + writer.WriteBit(false); //VUI parameter present flag + + writer.End(); + + // Picture Parameter Set. + writer.WriteU(1, 24); + writer.WriteU(0, 1); + writer.WriteU(3, 2); + writer.WriteU(8, 5); + + writer.WriteUe(0); + writer.WriteUe(0); + + writer.WriteBit(_entropyCodingModeFlag); + writer.WriteBit(false); + writer.WriteUe(0); + writer.WriteUe(_numRefIdxL0DefaultActiveMinus1); + writer.WriteUe(_numRefIdxL1DefaultActiveMinus1); + writer.WriteBit(_weightedPredFlag); + writer.WriteU(_weightedBipredIdc, 2); + writer.WriteSe(_picInitQpMinus26); + writer.WriteSe(0); + writer.WriteSe(_chromaQpIndexOffset); + writer.WriteBit(_deblockingFilterControlPresentFlag); + writer.WriteBit(_constrainedIntraPredFlag); + writer.WriteBit(_redundantPicCntPresentFlag); + writer.WriteBit(_transform8x8ModeFlag); + + writer.WriteBit(true); + + for (int index = 0; index < 6; index++) + { + writer.WriteBit(true); + + WriteScalingList(writer, _scalingMatrix4, index * 16, 16); + } + + if (_transform8x8ModeFlag) + { + for (int index = 0; index < 2; index++) + { + writer.WriteBit(true); + + WriteScalingList(writer, _scalingMatrix8, index * 64, 64); + } + } + + writer.WriteSe(_chromaQpIndexOffset2); + + writer.End(); + + return data.ToArray(); + } + } + + // ZigZag LUTs from libavcodec. + private static readonly byte[] ZigZagDirect = new byte[] + { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 + }; + + private static readonly byte[] ZigZagScan = new byte[] + { + 0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, + 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4, + 1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4, + 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4 + }; + + private static void WriteScalingList(H264BitStreamWriter writer, byte[] list, int start, int count) + { + byte[] scan = count == 16 ? ZigZagScan : ZigZagDirect; + + int lastScale = 8; + + for (int index = 0; index < count; index++) + { + byte value = list[start + scan[index]]; + + int deltaScale = value - lastScale; + + writer.WriteSe(deltaScale); + + lastScale = value; + } + } + } +}
\ No newline at end of file |
