DecoderCommon.cs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. using Concentus;
  2. using Concentus.Enums;
  3. using Concentus.Structs;
  4. using Ryujinx.HLE.HOS.Services.Audio.Types;
  5. using System;
  6. using System.Runtime.CompilerServices;
  7. namespace Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager
  8. {
  9. static class DecoderCommon
  10. {
  11. private static ResultCode GetPacketNumSamples(this IDecoder decoder, out int numSamples, byte[] packet)
  12. {
  13. int result = OpusPacketInfo.GetNumSamples(packet, 0, packet.Length, decoder.SampleRate);
  14. numSamples = result;
  15. if (result == OpusError.OPUS_INVALID_PACKET)
  16. {
  17. return ResultCode.OpusInvalidInput;
  18. }
  19. else if (result == OpusError.OPUS_BAD_ARG)
  20. {
  21. return ResultCode.OpusInvalidInput;
  22. }
  23. return ResultCode.Success;
  24. }
  25. public static ResultCode DecodeInterleaved(
  26. this IDecoder decoder,
  27. bool reset,
  28. ReadOnlySpan<byte> input,
  29. out short[] outPcmData,
  30. ulong outputSize,
  31. out uint outConsumed,
  32. out int outSamples)
  33. {
  34. outPcmData = null;
  35. outConsumed = 0;
  36. outSamples = 0;
  37. int streamSize = input.Length;
  38. if (streamSize < Unsafe.SizeOf<OpusPacketHeader>())
  39. {
  40. return ResultCode.OpusInvalidInput;
  41. }
  42. OpusPacketHeader header = OpusPacketHeader.FromSpan(input);
  43. int headerSize = Unsafe.SizeOf<OpusPacketHeader>();
  44. uint totalSize = header.length + (uint)headerSize;
  45. if (totalSize > streamSize)
  46. {
  47. return ResultCode.OpusInvalidInput;
  48. }
  49. byte[] opusData = input.Slice(headerSize, (int)header.length).ToArray();
  50. ResultCode result = decoder.GetPacketNumSamples(out int numSamples, opusData);
  51. if (result == ResultCode.Success)
  52. {
  53. if ((uint)numSamples * (uint)decoder.ChannelsCount * sizeof(short) > outputSize)
  54. {
  55. return ResultCode.OpusInvalidInput;
  56. }
  57. outPcmData = new short[numSamples * decoder.ChannelsCount];
  58. if (reset)
  59. {
  60. decoder.ResetState();
  61. }
  62. try
  63. {
  64. outSamples = decoder.Decode(opusData, 0, opusData.Length, outPcmData, 0, outPcmData.Length / decoder.ChannelsCount);
  65. outConsumed = totalSize;
  66. }
  67. catch (OpusException)
  68. {
  69. // TODO: as OpusException doesn't provide us the exact error code, this is kind of inaccurate in some cases...
  70. return ResultCode.OpusInvalidInput;
  71. }
  72. }
  73. return ResultCode.Success;
  74. }
  75. }
  76. }