diff options
Diffstat (limited to 'Ryujinx.Graphics/VDec/H264Decoder.cs')
| -rw-r--r-- | Ryujinx.Graphics/VDec/H264Decoder.cs | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/VDec/H264Decoder.cs b/Ryujinx.Graphics/VDec/H264Decoder.cs new file mode 100644 index 00000000..d5d46713 --- /dev/null +++ b/Ryujinx.Graphics/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 |
