H264BitStreamWriter.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. using System;
  2. using System.Numerics;
  3. namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
  4. {
  5. struct H264BitStreamWriter
  6. {
  7. private const int BufferSize = 8;
  8. private readonly byte[] _workBuffer;
  9. private int _offset;
  10. private int _buffer;
  11. private int _bufferPos;
  12. public H264BitStreamWriter(byte[] workBuffer)
  13. {
  14. _workBuffer = workBuffer;
  15. _offset = 0;
  16. _buffer = 0;
  17. _bufferPos = 0;
  18. }
  19. public void WriteBit(bool value)
  20. {
  21. WriteBits(value ? 1 : 0, 1);
  22. }
  23. public void WriteBits(int value, int valueSize)
  24. {
  25. int valuePos = 0;
  26. int remaining = valueSize;
  27. while (remaining > 0)
  28. {
  29. int copySize = remaining;
  30. int free = GetFreeBufferBits();
  31. if (copySize > free)
  32. {
  33. copySize = free;
  34. }
  35. int mask = (1 << copySize) - 1;
  36. int srcShift = (valueSize - valuePos) - copySize;
  37. int dstShift = (BufferSize - _bufferPos) - copySize;
  38. _buffer |= ((value >> srcShift) & mask) << dstShift;
  39. valuePos += copySize;
  40. _bufferPos += copySize;
  41. remaining -= copySize;
  42. }
  43. }
  44. private int GetFreeBufferBits()
  45. {
  46. if (_bufferPos == BufferSize)
  47. {
  48. Flush();
  49. }
  50. return BufferSize - _bufferPos;
  51. }
  52. public void Flush()
  53. {
  54. if (_bufferPos != 0)
  55. {
  56. _workBuffer[_offset++] = (byte)_buffer;
  57. _buffer = 0;
  58. _bufferPos = 0;
  59. }
  60. }
  61. public void End()
  62. {
  63. WriteBit(true);
  64. Flush();
  65. }
  66. public Span<byte> AsSpan()
  67. {
  68. return new Span<byte>(_workBuffer).Slice(0, _offset);
  69. }
  70. public void WriteU(uint value, int valueSize) => WriteBits((int)value, valueSize);
  71. public void WriteSe(int value) => WriteExpGolombCodedInt(value);
  72. public void WriteUe(uint value) => WriteExpGolombCodedUInt(value);
  73. private void WriteExpGolombCodedInt(int value)
  74. {
  75. int sign = value <= 0 ? 0 : 1;
  76. if (value < 0)
  77. {
  78. value = -value;
  79. }
  80. value = (value << 1) - sign;
  81. WriteExpGolombCodedUInt((uint)value);
  82. }
  83. private void WriteExpGolombCodedUInt(uint value)
  84. {
  85. int size = 32 - BitOperations.LeadingZeroCount(value + 1);
  86. WriteBits(1, size);
  87. value -= (1u << (size - 1)) - 1;
  88. WriteBits((int)value, size - 1);
  89. }
  90. }
  91. }