aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Nvdec.H264
diff options
context:
space:
mode:
authorAc_K <Acoustik666@gmail.com>2021-10-12 22:55:57 +0200
committerGitHub <noreply@github.com>2021-10-12 22:55:57 +0200
commitd1604aa762a3f669a3fecff0a30b7360399954bc (patch)
tree1996eec4b3937354aedc4d31b5b7b931ae4e321b /Ryujinx.Graphics.Nvdec.H264
parenta7109c767bdc014327b574012794156c92174495 (diff)
nvdec: Adding Vp8 codec support (#2707)
* first try * second try * working update * Final impl * Fixes nits * Fix everything * remove leftover * Update FFmpegContext.cs * Update Surface.cs * Addresses gdkchan feedback * bool not byte * Addresses gdkchan feedback
Diffstat (limited to 'Ryujinx.Graphics.Nvdec.H264')
-rw-r--r--Ryujinx.Graphics.Nvdec.H264/Decoder.cs55
-rw-r--r--Ryujinx.Graphics.Nvdec.H264/FFmpegContext.cs162
-rw-r--r--Ryujinx.Graphics.Nvdec.H264/H264BitStreamWriter.cs121
-rw-r--r--Ryujinx.Graphics.Nvdec.H264/Ryujinx.Graphics.Nvdec.H264.csproj16
-rw-r--r--Ryujinx.Graphics.Nvdec.H264/SpsAndPpsReconstruction.cs159
-rw-r--r--Ryujinx.Graphics.Nvdec.H264/Surface.cs39
6 files changed, 0 insertions, 552 deletions
diff --git a/Ryujinx.Graphics.Nvdec.H264/Decoder.cs b/Ryujinx.Graphics.Nvdec.H264/Decoder.cs
deleted file mode 100644
index fed64af4..00000000
--- a/Ryujinx.Graphics.Nvdec.H264/Decoder.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using Ryujinx.Graphics.Video;
-using System;
-
-namespace Ryujinx.Graphics.Nvdec.H264
-{
- public sealed class Decoder : IH264Decoder
- {
- public bool IsHardwareAccelerated => false;
-
- private const int WorkBufferSize = 0x200;
-
- private readonly byte[] _workBuffer = new byte[WorkBufferSize];
-
- private FFmpegContext _context = new FFmpegContext();
-
- private int _oldOutputWidth;
- private int _oldOutputHeight;
-
- public ISurface CreateSurface(int width, int height)
- {
- return new Surface(width, height);
- }
-
- public bool Decode(ref H264PictureInfo pictureInfo, ISurface output, ReadOnlySpan<byte> bitstream)
- {
- Surface outSurf = (Surface)output;
-
- if (outSurf.RequestedWidth != _oldOutputWidth ||
- outSurf.RequestedHeight != _oldOutputHeight)
- {
- _context.Dispose();
- _context = new FFmpegContext();
-
- _oldOutputWidth = outSurf.RequestedWidth;
- _oldOutputHeight = outSurf.RequestedHeight;
- }
-
- Span<byte> bs = Prepend(bitstream, SpsAndPpsReconstruction.Reconstruct(ref pictureInfo, _workBuffer));
-
- return _context.DecodeFrame(outSurf, bs) == 0;
- }
-
- private static byte[] Prepend(ReadOnlySpan<byte> data, ReadOnlySpan<byte> prep)
- {
- byte[] output = new byte[data.Length + prep.Length];
-
- prep.CopyTo(output);
- data.CopyTo(new Span<byte>(output).Slice(prep.Length));
-
- return output;
- }
-
- public void Dispose() => _context.Dispose();
- }
-}
diff --git a/Ryujinx.Graphics.Nvdec.H264/FFmpegContext.cs b/Ryujinx.Graphics.Nvdec.H264/FFmpegContext.cs
deleted file mode 100644
index 66b1e6c1..00000000
--- a/Ryujinx.Graphics.Nvdec.H264/FFmpegContext.cs
+++ /dev/null
@@ -1,162 +0,0 @@
-using FFmpeg.AutoGen;
-using Ryujinx.Common.Logging;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Nvdec.H264
-{
- unsafe class FFmpegContext : IDisposable
- {
- private readonly AVCodec_decode _h264Decode;
- private static readonly av_log_set_callback_callback _logFunc;
- private readonly AVCodec* _codec;
- private AVPacket* _packet;
- private AVCodecContext* _context;
-
- public FFmpegContext()
- {
- _codec = ffmpeg.avcodec_find_decoder(AVCodecID.AV_CODEC_ID_H264);
- _context = ffmpeg.avcodec_alloc_context3(_codec);
- _context->debug |= ffmpeg.FF_DEBUG_MMCO;
-
- ffmpeg.avcodec_open2(_context, _codec, null);
-
- _packet = ffmpeg.av_packet_alloc();
-
- _h264Decode = Marshal.GetDelegateForFunctionPointer<AVCodec_decode>(_codec->decode.Pointer);
- }
-
- static FFmpegContext()
- {
- SetRootPath();
-
- _logFunc = Log;
-
- // Redirect log output.
- ffmpeg.av_log_set_level(ffmpeg.AV_LOG_MAX_OFFSET);
- ffmpeg.av_log_set_callback(_logFunc);
- }
-
- private static void SetRootPath()
- {
- if (OperatingSystem.IsLinux())
- {
- // Configure FFmpeg search path
- Process lddProcess = Process.Start(new ProcessStartInfo
- {
- FileName = "/bin/sh",
- Arguments = "-c \"ldd $(which ffmpeg 2>/dev/null) | grep libavfilter\" 2>/dev/null",
- UseShellExecute = false,
- RedirectStandardOutput = true
- });
-
- string lddOutput = lddProcess.StandardOutput.ReadToEnd();
-
- lddProcess.WaitForExit();
- lddProcess.Close();
-
- if (lddOutput.Contains(" => "))
- {
- ffmpeg.RootPath = Path.GetDirectoryName(lddOutput.Split(" => ")[1]);
- }
- else
- {
- Logger.Error?.PrintMsg(LogClass.FFmpeg, "FFmpeg wasn't found. Make sure that you have it installed and up to date.");
- }
- }
- }
-
- private static void Log(void* p0, int level, string format, byte* vl)
- {
- if (level > ffmpeg.av_log_get_level())
- {
- return;
- }
-
- int lineSize = 1024;
- byte* lineBuffer = stackalloc byte[lineSize];
- int printPrefix = 1;
-
- ffmpeg.av_log_format_line(p0, level, format, vl, lineBuffer, lineSize, &printPrefix);
-
- string line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer).Trim();
-
- switch (level)
- {
- case ffmpeg.AV_LOG_PANIC:
- case ffmpeg.AV_LOG_FATAL:
- case ffmpeg.AV_LOG_ERROR:
- Logger.Error?.Print(LogClass.FFmpeg, line);
- break;
- case ffmpeg.AV_LOG_WARNING:
- Logger.Warning?.Print(LogClass.FFmpeg, line);
- break;
- case ffmpeg.AV_LOG_INFO:
- Logger.Info?.Print(LogClass.FFmpeg, line);
- break;
- case ffmpeg.AV_LOG_VERBOSE:
- case ffmpeg.AV_LOG_DEBUG:
- case ffmpeg.AV_LOG_TRACE:
- Logger.Debug?.Print(LogClass.FFmpeg, line);
- break;
- }
- }
-
- public int DecodeFrame(Surface output, ReadOnlySpan<byte> bitstream)
- {
- ffmpeg.av_frame_unref(output.Frame);
-
- int result;
- int gotFrame;
-
- fixed (byte* ptr = bitstream)
- {
- _packet->data = ptr;
- _packet->size = bitstream.Length;
- result = _h264Decode(_context, output.Frame, &gotFrame, _packet);
- }
-
- if (gotFrame == 0)
- {
- ffmpeg.av_frame_unref(output.Frame);
-
- // If the frame was not delivered, it was probably delayed.
- // Get the next delayed frame by passing a 0 length packet.
- _packet->data = null;
- _packet->size = 0;
- result = _h264Decode(_context, output.Frame, &gotFrame, _packet);
-
- // We need to set B frames to 0 as we already consumed all delayed frames.
- // This prevents the decoder from trying to return a delayed frame next time.
- _context->has_b_frames = 0;
- }
-
- ffmpeg.av_packet_unref(_packet);
-
- if (gotFrame == 0)
- {
- ffmpeg.av_frame_unref(output.Frame);
- return -1;
- }
-
- return result < 0 ? result : 0;
- }
-
- public void Dispose()
- {
- fixed (AVPacket** ppPacket = &_packet)
- {
- ffmpeg.av_packet_free(ppPacket);
- }
-
- ffmpeg.avcodec_close(_context);
-
- fixed (AVCodecContext** ppContext = &_context)
- {
- ffmpeg.avcodec_free_context(ppContext);
- }
- }
- }
-}
diff --git a/Ryujinx.Graphics.Nvdec.H264/H264BitStreamWriter.cs b/Ryujinx.Graphics.Nvdec.H264/H264BitStreamWriter.cs
deleted file mode 100644
index c0e2357d..00000000
--- a/Ryujinx.Graphics.Nvdec.H264/H264BitStreamWriter.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using System;
-using System.Numerics;
-
-namespace Ryujinx.Graphics.Nvdec.H264
-{
- struct H264BitStreamWriter
- {
- private const int BufferSize = 8;
-
- private readonly byte[] _workBuffer;
-
- private int _offset;
- private int _buffer;
- private int _bufferPos;
-
- public H264BitStreamWriter(byte[] workBuffer)
- {
- _workBuffer = workBuffer;
- _offset = 0;
- _buffer = 0;
- _bufferPos = 0;
- }
-
- public void WriteBit(bool value)
- {
- WriteBits(value ? 1 : 0, 1);
- }
-
- public void WriteBits(int value, int valueSize)
- {
- int valuePos = 0;
-
- int remaining = valueSize;
-
- while (remaining > 0)
- {
- int copySize = remaining;
-
- int free = GetFreeBufferBits();
-
- if (copySize > free)
- {
- copySize = free;
- }
-
- int mask = (1 << copySize) - 1;
-
- int srcShift = (valueSize - valuePos) - copySize;
- int dstShift = (BufferSize - _bufferPos) - copySize;
-
- _buffer |= ((value >> srcShift) & mask) << dstShift;
-
- valuePos += copySize;
- _bufferPos += copySize;
- remaining -= copySize;
- }
- }
-
- private int GetFreeBufferBits()
- {
- if (_bufferPos == BufferSize)
- {
- Flush();
- }
-
- return BufferSize - _bufferPos;
- }
-
- public void Flush()
- {
- if (_bufferPos != 0)
- {
- _workBuffer[_offset++] = (byte)_buffer;
-
- _buffer = 0;
- _bufferPos = 0;
- }
- }
-
- public void End()
- {
- WriteBit(true);
-
- Flush();
- }
-
- public Span<byte> AsSpan()
- {
- return new Span<byte>(_workBuffer).Slice(0, _offset);
- }
-
- public void WriteU(uint value, int valueSize) => WriteBits((int)value, valueSize);
- public void WriteSe(int value) => WriteExpGolombCodedInt(value);
- public void WriteUe(uint value) => WriteExpGolombCodedUInt(value);
-
- private void WriteExpGolombCodedInt(int value)
- {
- int sign = value <= 0 ? 0 : 1;
-
- if (value < 0)
- {
- value = -value;
- }
-
- value = (value << 1) - sign;
-
- WriteExpGolombCodedUInt((uint)value);
- }
-
- private void WriteExpGolombCodedUInt(uint value)
- {
- int size = 32 - BitOperations.LeadingZeroCount(value + 1);
-
- WriteBits(1, size);
-
- value -= (1u << (size - 1)) - 1;
-
- WriteBits((int)value, size - 1);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Nvdec.H264/Ryujinx.Graphics.Nvdec.H264.csproj b/Ryujinx.Graphics.Nvdec.H264/Ryujinx.Graphics.Nvdec.H264.csproj
deleted file mode 100644
index fdcdae06..00000000
--- a/Ryujinx.Graphics.Nvdec.H264/Ryujinx.Graphics.Nvdec.H264.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>net5.0</TargetFramework>
- <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="FFmpeg.AutoGen" Version="4.4.0" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />
- </ItemGroup>
-
-</Project>
diff --git a/Ryujinx.Graphics.Nvdec.H264/SpsAndPpsReconstruction.cs b/Ryujinx.Graphics.Nvdec.H264/SpsAndPpsReconstruction.cs
deleted file mode 100644
index 6fd1ce79..00000000
--- a/Ryujinx.Graphics.Nvdec.H264/SpsAndPpsReconstruction.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-using Ryujinx.Common.Memory;
-using Ryujinx.Graphics.Video;
-using System;
-
-namespace Ryujinx.Graphics.Nvdec.H264
-{
- static class SpsAndPpsReconstruction
- {
- public static Span<byte> Reconstruct(ref H264PictureInfo pictureInfo, byte[] workBuffer)
- {
- H264BitStreamWriter writer = new H264BitStreamWriter(workBuffer);
-
- // Sequence Parameter Set.
- writer.WriteU(1, 24);
- writer.WriteU(0, 1);
- writer.WriteU(3, 2);
- writer.WriteU(7, 5);
- writer.WriteU(100, 8); // Profile idc
- writer.WriteU(0, 8); // Reserved
- writer.WriteU(31, 8); // Level idc
- writer.WriteUe(0); // Seq parameter set id
- writer.WriteUe(pictureInfo.ChromaFormatIdc);
-
- if (pictureInfo.ChromaFormatIdc == 3)
- {
- writer.WriteBit(false); // Separate colour plane flag
- }
-
- writer.WriteUe(0); // Bit depth luma minus 8
- writer.WriteUe(0); // Bit depth chroma minus 8
- writer.WriteBit(pictureInfo.QpprimeYZeroTransformBypassFlag);
- writer.WriteBit(false); // Scaling matrix present flag
-
- writer.WriteUe(pictureInfo.Log2MaxFrameNumMinus4);
- writer.WriteUe(pictureInfo.PicOrderCntType);
-
- if (pictureInfo.PicOrderCntType == 0)
- {
- writer.WriteUe(pictureInfo.Log2MaxPicOrderCntLsbMinus4);
- }
- else if (pictureInfo.PicOrderCntType == 1)
- {
- writer.WriteBit(pictureInfo.DeltaPicOrderAlwaysZeroFlag);
-
- writer.WriteSe(0); // Offset for non-ref pic
- writer.WriteSe(0); // Offset for top to bottom field
- writer.WriteUe(0); // Num ref frames in pic order cnt cycle
- }
-
- writer.WriteUe(16); // Max num ref frames
- writer.WriteBit(false); // Gaps in frame num value allowed flag
- writer.WriteUe(pictureInfo.PicWidthInMbsMinus1);
- writer.WriteUe(pictureInfo.PicHeightInMapUnitsMinus1);
- writer.WriteBit(pictureInfo.FrameMbsOnlyFlag);
-
- if (!pictureInfo.FrameMbsOnlyFlag)
- {
- writer.WriteBit(pictureInfo.MbAdaptiveFrameFieldFlag);
- }
-
- writer.WriteBit(pictureInfo.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); // Pic parameter set id
- writer.WriteUe(0); // Seq parameter set id
-
- writer.WriteBit(pictureInfo.EntropyCodingModeFlag);
- writer.WriteBit(pictureInfo.PicOrderPresentFlag);
- writer.WriteUe(0); // Num slice groups minus 1
- writer.WriteUe(pictureInfo.NumRefIdxL0ActiveMinus1);
- writer.WriteUe(pictureInfo.NumRefIdxL1ActiveMinus1);
- writer.WriteBit(pictureInfo.WeightedPredFlag);
- writer.WriteU(pictureInfo.WeightedBipredIdc, 2);
- writer.WriteSe(pictureInfo.PicInitQpMinus26);
- writer.WriteSe(0); // Pic init qs minus 26
- writer.WriteSe(pictureInfo.ChromaQpIndexOffset);
- writer.WriteBit(pictureInfo.DeblockingFilterControlPresentFlag);
- writer.WriteBit(pictureInfo.ConstrainedIntraPredFlag);
- writer.WriteBit(pictureInfo.RedundantPicCntPresentFlag);
- writer.WriteBit(pictureInfo.Transform8x8ModeFlag);
-
- writer.WriteBit(pictureInfo.ScalingMatrixPresent);
-
- if (pictureInfo.ScalingMatrixPresent)
- {
- for (int index = 0; index < 6; index++)
- {
- writer.WriteBit(true);
-
- WriteScalingList(ref writer, pictureInfo.ScalingLists4x4[index]);
- }
-
- if (pictureInfo.Transform8x8ModeFlag)
- {
- for (int index = 0; index < 2; index++)
- {
- writer.WriteBit(true);
-
- WriteScalingList(ref writer, pictureInfo.ScalingLists8x8[index]);
- }
- }
- }
-
- writer.WriteSe(pictureInfo.SecondChromaQpIndexOffset);
-
- writer.End();
-
- return writer.AsSpan();
- }
-
- // 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(ref H264BitStreamWriter writer, IArray<byte> list)
- {
- byte[] scan = list.Length == 16 ? ZigZagScan : ZigZagDirect;
-
- int lastScale = 8;
-
- for (int index = 0; index < list.Length; index++)
- {
- byte value = list[scan[index]];
-
- int deltaScale = value - lastScale;
-
- writer.WriteSe(deltaScale);
-
- lastScale = value;
- }
- }
- }
-}
diff --git a/Ryujinx.Graphics.Nvdec.H264/Surface.cs b/Ryujinx.Graphics.Nvdec.H264/Surface.cs
deleted file mode 100644
index 3dbc980e..00000000
--- a/Ryujinx.Graphics.Nvdec.H264/Surface.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using FFmpeg.AutoGen;
-using Ryujinx.Graphics.Video;
-using System;
-
-namespace Ryujinx.Graphics.Nvdec.H264
-{
- unsafe class Surface : ISurface
- {
- public AVFrame* Frame { get; }
-
- public int RequestedWidth { get; }
- public int RequestedHeight { get; }
-
- public Plane YPlane => new Plane((IntPtr)Frame->data[0], Stride * Height);
- public Plane UPlane => new Plane((IntPtr)Frame->data[1], UvStride * UvHeight);
- public Plane VPlane => new Plane((IntPtr)Frame->data[2], UvStride * UvHeight);
-
- public int Width => Frame->width;
- public int Height => Frame->height;
- public int Stride => Frame->linesize[0];
- public int UvWidth => (Frame->width + 1) >> 1;
- public int UvHeight => (Frame->height + 1) >> 1;
- public int UvStride => Frame->linesize[1];
-
- public Surface(int width, int height)
- {
- RequestedWidth = width;
- RequestedHeight = height;
-
- Frame = ffmpeg.av_frame_alloc();
- }
-
- public void Dispose()
- {
- ffmpeg.av_frame_unref(Frame);
- ffmpeg.av_free(Frame);
- }
- }
-}