| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- using ChocolArm64.Memory;
- using Ryujinx.Graphics.Gal;
- using Ryujinx.Graphics.Memory;
- using Ryujinx.Graphics.Texture;
- using Ryujinx.Graphics.Vic;
- using System;
- namespace Ryujinx.Graphics.VDec
- {
- unsafe class VideoDecoder
- {
- private NvGpu Gpu;
- private H264Decoder H264Decoder;
- private Vp9Decoder Vp9Decoder;
- private VideoCodec CurrentVideoCodec;
- private long DecoderContextAddress;
- private long FrameDataAddress;
- private long VpxCurrLumaAddress;
- private long VpxRef0LumaAddress;
- private long VpxRef1LumaAddress;
- private long VpxRef2LumaAddress;
- private long VpxCurrChromaAddress;
- private long VpxRef0ChromaAddress;
- private long VpxRef1ChromaAddress;
- private long VpxRef2ChromaAddress;
- private long VpxProbTablesAddress;
- public VideoDecoder(NvGpu Gpu)
- {
- this.Gpu = Gpu;
- H264Decoder = new H264Decoder();
- Vp9Decoder = new Vp9Decoder();
- }
- public void Process(NvGpuVmm Vmm, int MethodOffset, int[] Arguments)
- {
- VideoDecoderMeth Method = (VideoDecoderMeth)MethodOffset;
- switch (Method)
- {
- case VideoDecoderMeth.SetVideoCodec: SetVideoCodec (Vmm, Arguments); break;
- case VideoDecoderMeth.Execute: Execute (Vmm, Arguments); break;
- case VideoDecoderMeth.SetDecoderCtxAddr: SetDecoderCtxAddr (Vmm, Arguments); break;
- case VideoDecoderMeth.SetFrameDataAddr: SetFrameDataAddr (Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxCurrLumaAddr: SetVpxCurrLumaAddr (Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxRef0LumaAddr: SetVpxRef0LumaAddr (Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxRef1LumaAddr: SetVpxRef1LumaAddr (Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxRef2LumaAddr: SetVpxRef2LumaAddr (Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxCurrChromaAddr: SetVpxCurrChromaAddr(Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxRef0ChromaAddr: SetVpxRef0ChromaAddr(Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxRef1ChromaAddr: SetVpxRef1ChromaAddr(Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxRef2ChromaAddr: SetVpxRef2ChromaAddr(Vmm, Arguments); break;
- case VideoDecoderMeth.SetVpxProbTablesAddr: SetVpxProbTablesAddr(Vmm, Arguments); break;
- }
- }
- private void SetVideoCodec(NvGpuVmm Vmm, int[] Arguments)
- {
- CurrentVideoCodec = (VideoCodec)Arguments[0];
- }
- private void Execute(NvGpuVmm Vmm, int[] Arguments)
- {
- if (CurrentVideoCodec == VideoCodec.H264)
- {
- int FrameDataSize = Vmm.ReadInt32(DecoderContextAddress + 0x48);
- H264ParameterSets Params = MemoryHelper.Read<H264ParameterSets>(Vmm.Memory, Vmm.GetPhysicalAddress(DecoderContextAddress + 0x58));
- H264Matrices Matrices = new H264Matrices()
- {
- ScalingMatrix4 = Vmm.ReadBytes(DecoderContextAddress + 0x1c0, 6 * 16),
- ScalingMatrix8 = Vmm.ReadBytes(DecoderContextAddress + 0x220, 2 * 64)
- };
- byte[] FrameData = Vmm.ReadBytes(FrameDataAddress, FrameDataSize);
- H264Decoder.Decode(Params, Matrices, FrameData);
- }
- else if (CurrentVideoCodec == VideoCodec.Vp9)
- {
- int FrameDataSize = Vmm.ReadInt32(DecoderContextAddress + 0x30);
- Vp9FrameKeys Keys = new Vp9FrameKeys()
- {
- CurrKey = Vmm.GetPhysicalAddress(VpxCurrLumaAddress),
- Ref0Key = Vmm.GetPhysicalAddress(VpxRef0LumaAddress),
- Ref1Key = Vmm.GetPhysicalAddress(VpxRef1LumaAddress),
- Ref2Key = Vmm.GetPhysicalAddress(VpxRef2LumaAddress)
- };
- Vp9FrameHeader Header = MemoryHelper.Read<Vp9FrameHeader>(Vmm.Memory, Vmm.GetPhysicalAddress(DecoderContextAddress + 0x48));
- Vp9ProbabilityTables Probs = new Vp9ProbabilityTables()
- {
- SegmentationTreeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x387, 0x7),
- SegmentationPredProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x38e, 0x3),
- Tx8x8Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x470, 0x2),
- Tx16x16Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x472, 0x4),
- Tx32x32Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x476, 0x6),
- CoefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x5a0, 0x900),
- SkipProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x537, 0x3),
- InterModeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x400, 0x1c),
- InterpFilterProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x52a, 0x8),
- IsInterProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x41c, 0x4),
- CompModeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x532, 0x5),
- SingleRefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x580, 0xa),
- CompRefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x58a, 0x5),
- YModeProbs0 = Vmm.ReadBytes(VpxProbTablesAddress + 0x480, 0x20),
- YModeProbs1 = Vmm.ReadBytes(VpxProbTablesAddress + 0x47c, 0x4),
- PartitionProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x4e0, 0x40),
- MvJointProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x53b, 0x3),
- MvSignProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x53e, 0x3),
- MvClassProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x54c, 0x14),
- MvClass0BitProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x540, 0x3),
- MvBitsProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x56c, 0x14),
- MvClass0FrProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x560, 0xc),
- MvFrProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x542, 0x6),
- MvClass0HpProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x548, 0x2),
- MvHpProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x54a, 0x2)
- };
- byte[] FrameData = Vmm.ReadBytes(FrameDataAddress, FrameDataSize);
- Vp9Decoder.Decode(Keys, Header, Probs, FrameData);
- }
- else
- {
- ThrowUnimplementedCodec();
- }
- }
- private void SetDecoderCtxAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- DecoderContextAddress = GetAddress(Arguments);
- }
- private void SetFrameDataAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- FrameDataAddress = GetAddress(Arguments);
- }
- private void SetVpxCurrLumaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxCurrLumaAddress = GetAddress(Arguments);
- }
- private void SetVpxRef0LumaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxRef0LumaAddress = GetAddress(Arguments);
- }
- private void SetVpxRef1LumaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxRef1LumaAddress = GetAddress(Arguments);
- }
- private void SetVpxRef2LumaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxRef2LumaAddress = GetAddress(Arguments);
- }
- private void SetVpxCurrChromaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxCurrChromaAddress = GetAddress(Arguments);
- }
- private void SetVpxRef0ChromaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxRef0ChromaAddress = GetAddress(Arguments);
- }
- private void SetVpxRef1ChromaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxRef1ChromaAddress = GetAddress(Arguments);
- }
- private void SetVpxRef2ChromaAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxRef2ChromaAddress = GetAddress(Arguments);
- }
- private void SetVpxProbTablesAddr(NvGpuVmm Vmm, int[] Arguments)
- {
- VpxProbTablesAddress = GetAddress(Arguments);
- }
- private static long GetAddress(int[] Arguments)
- {
- return (long)(uint)Arguments[0] << 8;
- }
- internal void CopyPlanes(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig)
- {
- switch (OutputConfig.PixelFormat)
- {
- case SurfacePixelFormat.RGBA8: CopyPlanesRgba8 (Vmm, OutputConfig); break;
- case SurfacePixelFormat.YUV420P: CopyPlanesYuv420p(Vmm, OutputConfig); break;
- default: ThrowUnimplementedPixelFormat(OutputConfig.PixelFormat); break;
- }
- }
- private void CopyPlanesRgba8(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig)
- {
- FFmpegFrame Frame = FFmpegWrapper.GetFrameRgba();
- if ((Frame.Width | Frame.Height) == 0)
- {
- return;
- }
- GalImage Image = new GalImage(
- OutputConfig.SurfaceWidth,
- OutputConfig.SurfaceHeight, 1,
- OutputConfig.GobBlockHeight,
- GalMemoryLayout.BlockLinear,
- GalImageFormat.RGBA8 | GalImageFormat.Unorm);
- ImageUtils.WriteTexture(Vmm, Image, Vmm.GetPhysicalAddress(OutputConfig.SurfaceLumaAddress), Frame.Data);
- }
- private void CopyPlanesYuv420p(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig)
- {
- FFmpegFrame Frame = FFmpegWrapper.GetFrame();
- if ((Frame.Width | Frame.Height) == 0)
- {
- return;
- }
- int HalfSrcWidth = Frame.Width / 2;
- int HalfWidth = Frame.Width / 2;
- int HalfHeight = Frame.Height / 2;
- int AlignedWidth = (OutputConfig.SurfaceWidth + 0xff) & ~0xff;
- for (int Y = 0; Y < Frame.Height; Y++)
- {
- int Src = Y * Frame.Width;
- int Dst = Y * AlignedWidth;
- int Size = Frame.Width;
- for (int Offset = 0; Offset < Size; Offset++)
- {
- Vmm.WriteByte(OutputConfig.SurfaceLumaAddress + Dst + Offset, *(Frame.LumaPtr + Src + Offset));
- }
- }
- //Copy chroma data from both channels with interleaving.
- for (int Y = 0; Y < HalfHeight; Y++)
- {
- int Src = Y * HalfSrcWidth;
- int Dst = Y * AlignedWidth;
- for (int X = 0; X < HalfWidth; X++)
- {
- Vmm.WriteByte(OutputConfig.SurfaceChromaUAddress + Dst + X * 2 + 0, *(Frame.ChromaBPtr + Src + X));
- Vmm.WriteByte(OutputConfig.SurfaceChromaUAddress + Dst + X * 2 + 1, *(Frame.ChromaRPtr + Src + X));
- }
- }
- }
- private void ThrowUnimplementedCodec()
- {
- throw new NotImplementedException("Codec \"" + CurrentVideoCodec + "\" is not supported!");
- }
- private void ThrowUnimplementedPixelFormat(SurfacePixelFormat PixelFormat)
- {
- throw new NotImplementedException("Pixel format \"" + PixelFormat + "\" is not supported!");
- }
- }
- }
|