Browse Source

Merge branch 'avif-in-heif' into heic-support

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
73f4dce7af
  1. 3
      .gitattributes
  2. 17
      ImageSharp.sln
  3. 2
      shared-infrastructure
  4. 11
      src/ImageSharp/Formats/Heif/Av1/Av1BitDepth.cs
  5. 174
      src/ImageSharp/Formats/Heif/Av1/Av1BitStreamReader.cs
  6. 66
      src/ImageSharp/Formats/Heif/Av1/Av1BitStreamWriter.cs
  7. 17
      src/ImageSharp/Formats/Heif/Av1/Av1BlockModeInfo.cs
  8. 44
      src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs
  9. 12
      src/ImageSharp/Formats/Heif/Av1/Av1ColorFormat.cs
  10. 51
      src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs
  11. 8
      src/ImageSharp/Formats/Heif/Av1/Av1MainParseContext.cs
  12. 142
      src/ImageSharp/Formats/Heif/Av1/Av1Math.cs
  13. 62
      src/ImageSharp/Formats/Heif/Av1/Av1PartitionType.cs
  14. 11
      src/ImageSharp/Formats/Heif/Av1/Av1Plane.cs
  15. 22
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuChromoSamplePosition.cs
  16. 52
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs
  17. 21
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorPrimaries.cs
  18. 82
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuConstants.cs
  19. 15
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuConstraintDirectionalEnhancementFilterParameters.cs
  20. 13
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuDeltaLoopFilterParameters.cs
  21. 11
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuDeltaQParameters.cs
  22. 9
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFilmGrainParameters.cs
  23. 89
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs
  24. 19
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameSize.cs
  25. 12
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameType.cs
  26. 21
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuHeader.cs
  27. 9
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopFilterParameters.cs
  28. 9
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopRestorationParameters.cs
  29. 22
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuMatrixCoefficients.cs
  30. 13
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuMetadataType.cs
  31. 17
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs
  32. 15
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOrderHintInfo.cs
  33. 8
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuPartitionInfo.cs
  34. 19
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuQuantizationParameters.cs
  35. 1250
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
  36. 10
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReferenceMode.cs
  37. 9
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuRestorationType.cs
  38. 16
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSegmentationLevelFeature.cs
  39. 15
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSegmentationParameters.cs
  40. 71
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs
  41. 11
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceProfile.cs
  42. 11
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSkipModeParameters.cs
  43. 39
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuTileInfo.cs
  44. 25
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuTransferCharacteristics.cs
  45. 18
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuType.cs
  46. 26
      src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionMode.cs
  47. 73
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseQuantizer.cs
  48. 148
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransform.cs
  49. 27
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs
  50. 75
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs
  51. 11
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformMode.cs
  52. 30
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSize.cs
  53. 16
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs
  54. 49
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType.cs
  55. 9
      src/ImageSharp/Formats/Heif/Heif4CharCode.cs
  56. 5
      src/ImageSharp/Formats/Heif/Heif4CharCode.tt
  57. 3
      src/ImageSharp/Formats/Heif/HeifDecoderCore.cs
  58. 86
      tests/ImageSharp.Tests/Formats/Heif/Av1/Av1BitStreamTests.cs
  59. 32
      tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs
  60. 2
      tests/ImageSharp.Tests/TestImages.cs
  61. 3
      tests/Images/Input/Heif/jpeg444_xnconvert.avif

3
.gitattributes

@ -136,3 +136,6 @@
*.ico filter=lfs diff=lfs merge=lfs -text
*.cur filter=lfs diff=lfs merge=lfs -text
*.ani filter=lfs diff=lfs merge=lfs -text
*.heic filter=lfs diff=lfs merge=lfs -text
*.hif filter=lfs diff=lfs merge=lfs -text
*.avif filter=lfs diff=lfs merge=lfs -text

17
ImageSharp.sln

@ -37,8 +37,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
src\Directory.Build.targets = src\Directory.Build.targets
src\README.md = src\README.md
src\ImageSharp.ruleset = src\ImageSharp.ruleset
src\README.md = src\README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}"
@ -215,6 +215,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{5C9B68
ProjectSection(SolutionItems) = preProject
tests\Images\Input\Jpg\issues\issue-1076-invalid-subsampling.jpg = tests\Images\Input\Jpg\issues\issue-1076-invalid-subsampling.jpg
tests\Images\Input\Jpg\issues\issue-1221-identify-multi-frame.jpg = tests\Images\Input\Jpg\issues\issue-1221-identify-multi-frame.jpg
tests\Images\Input\Jpg\issues\issue-2067-comment.jpg = tests\Images\Input\Jpg\issues\issue-2067-comment.jpg
tests\Images\Input\Jpg\issues\issue1006-incorrect-resize.jpg = tests\Images\Input\Jpg\issues\issue1006-incorrect-resize.jpg
tests\Images\Input\Jpg\issues\issue1049-exif-resize.jpg = tests\Images\Input\Jpg\issues\issue1049-exif-resize.jpg
tests\Images\Input\Jpg\issues\Issue159-MissingFF00-Progressive-Bedroom.jpg = tests\Images\Input\Jpg\issues\Issue159-MissingFF00-Progressive-Bedroom.jpg
@ -238,7 +239,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{5C9B68
tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg = tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg
tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg = tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg
tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg = tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg
tests\Images\Input\Jpg\issues\issue-2067-comment.jpg = tests\Images\Input\Jpg\issues\issue-2067-comment.jpg
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fuzz", "fuzz", "{516A3532-6AC2-417B-AD79-9BD5D0D378A0}"
@ -661,6 +661,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Qoi", "Qoi", "{E801B508-493
tests\Images\Input\Qoi\wikipedia_008.qoi = tests\Images\Input\Qoi\wikipedia_008.qoi
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Heif", "Heif", "{BA5D603A-C84C-43E5-B300-8BB886B02936}"
ProjectSection(SolutionItems) = preProject
tests\Images\Input\Heif\dwsample-heic-640.heic = tests\Images\Input\Heif\dwsample-heic-640.heic
tests\Images\Input\Heif\image1.heic = tests\Images\Input\Heif\image1.heic
tests\Images\Input\Heif\image2.heic = tests\Images\Input\Heif\image2.heic
tests\Images\Input\Heif\image3.heic = tests\Images\Input\Heif\image3.heic
tests\Images\Input\Heif\image4.heic = tests\Images\Input\Heif\image4.heic
tests\Images\Input\Heif\IMG-20230508-0053.hif = tests\Images\Input\Heif\IMG-20230508-0053.hif
tests\Images\Input\Heif\Irvine_CA.avif = tests\Images\Input\Heif\Irvine_CA.avif
tests\Images\Input\Heif\jpeg444_xnconvert.avif = tests\Images\Input\Heif\jpeg444_xnconvert.avif
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -714,6 +726,7 @@ Global
{670DD46C-82E9-499A-B2D2-00A802ED0141} = {E1C42A6F-913B-4A7B-B1A8-2BB62843B254}
{5DFC394F-136F-4B76-9BCA-3BA786515EFC} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{E801B508-4935-41CD-BA85-CF11BFF55A45} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{BA5D603A-C84C-43E5-B300-8BB886B02936} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795}

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f
Subproject commit 922c5b21e5dfa02d4ef0d95334ab01c87a7a4309

11
src/ImageSharp/Formats/Heif/Av1/Av1BitDepth.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal enum Av1BitDepth : int
{
EightBit = 0,
TenBit = 1,
TwelveBit = 2,
}

174
src/ImageSharp/Formats/Heif/Av1/Av1BitStreamReader.cs

@ -0,0 +1,174 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal ref struct Av1BitStreamReader
{
private const int WordSize = 32;
private readonly Span<uint> data;
private uint currentWord;
private uint nextWord;
private int wordPosition = 0;
private int bitOffset = 0;
public Av1BitStreamReader(Span<byte> data)
{
this.data = MemoryMarshal.Cast<byte, uint>(data);
this.wordPosition = -1;
this.AdvanceToNextWord();
this.AdvanceToNextWord();
}
public readonly int BitPosition => ((this.wordPosition - 1) * WordSize) + this.bitOffset;
/// <summary>
/// Gets the number of bytes in the readers buffer.
/// </summary>
public readonly int Length => this.data.Length;
public void Reset()
{
this.wordPosition = 0;
this.bitOffset = 0;
}
public void Skip(int bitCount)
{
this.bitOffset += bitCount;
while (this.bitOffset >= WordSize)
{
this.bitOffset -= WordSize;
this.wordPosition++;
}
}
public uint ReadLiteral(int bitCount)
{
DebugGuard.MustBeBetweenOrEqualTo(bitCount, 0, 32, nameof(bitCount));
uint bits = (this.currentWord << this.bitOffset) >> (WordSize - bitCount);
this.bitOffset += bitCount;
if (this.bitOffset > WordSize)
{
int overshoot = WordSize + WordSize - this.bitOffset;
if (overshoot < 32)
{
bits |= this.nextWord >> overshoot;
}
}
if (this.bitOffset >= WordSize)
{
this.AdvanceToNextWord();
this.bitOffset -= WordSize;
}
return bits;
}
internal bool ReadBoolean() => this.ReadLiteral(1) > 0;
public ulong ReadLittleEndianBytes128(out int length)
{
// See section 4.10.5 of the AV1-Specification
DebugGuard.IsTrue((this.bitOffset & 0x07) == 0, $"Reading of Little Endian 128 value only allowed on byte alignment (offset {this.BitPosition}).");
ulong value = 0;
length = 0;
for (int i = 0; i < 56; i += 7)
{
uint leb128Byte = this.ReadLiteral(8);
value |= (leb128Byte & 0x7FUL) << i;
length++;
if ((leb128Byte & 0x80U) == 0)
{
break;
}
}
return value;
}
public uint ReadUnsignedVariableLength()
{
// See section 4.10.3 of the AV1-Specification
int leadingZerosCount = 0;
while (leadingZerosCount < 32 && this.ReadLiteral(1) == 0U)
{
leadingZerosCount++;
}
if (leadingZerosCount == 32)
{
return uint.MaxValue;
}
uint basis = (1U << leadingZerosCount) - 1U;
uint value = this.ReadLiteral(leadingZerosCount);
return basis + value;
}
public uint ReadNonSymmetric(uint n)
{
// See section 4.10.7 of the AV1-Specification
if (n <= 1)
{
return 0;
}
int w = (int)(Av1Math.FloorLog2(n) + 1);
uint m = (uint)((1 << w) - n);
uint v = this.ReadLiteral(w - 1);
if (v < m)
{
return v;
}
return (v << 1) - m + this.ReadLiteral(1);
}
public int ReadSignedFromUnsigned(int n)
{
// See section 4.10.6 of the AV1-Specification
int signedValue;
uint value = this.ReadLiteral(n);
uint signMask = 1U << (n - 1);
if ((value & signMask) == signMask)
{
// Prevent overflow by casting to long;
signedValue = (int)((long)value - (signMask << 1));
}
else
{
signedValue = (int)value;
}
return signedValue;
}
public uint ReadLittleEndian(int n)
{
// See section 4.10.4 of the AV1-Specification
DebugGuard.IsTrue((this.bitOffset & (WordSize - 1)) == 0, "Reading of Little Endian value only allowed on byte alignment");
uint t = 0;
for (int i = 0; i < 8 * n; i += 8)
{
t += this.ReadLiteral(8) << i;
}
return t;
}
public void AdvanceToNextWord()
{
this.currentWord = this.nextWord;
this.wordPosition++;
uint temp = this.data[this.wordPosition];
this.nextWord = (temp << 24) | ((temp & 0x0000ff00U) << 8) | ((temp & 0x00ff0000U) >> 8) | (temp >> 24);
}
}

66
src/ImageSharp/Formats/Heif/Av1/Av1BitStreamWriter.cs

@ -0,0 +1,66 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal ref struct Av1BitStreamWriter(Stream stream)
{
private const int WordSize = 8;
private readonly Stream stream = stream;
private byte buffer = 0;
private int bitOffset = 0;
public readonly int BitPosition => (int)(this.stream.Position * WordSize) + this.bitOffset;
public readonly int Length => (int)this.stream.Length;
public void Skip(int bitCount)
{
this.bitOffset += bitCount;
while (this.bitOffset >= WordSize)
{
this.bitOffset -= WordSize;
this.stream.WriteByte(this.buffer);
this.buffer = 0;
}
}
public void Flush()
{
this.stream.WriteByte(this.buffer);
this.bitOffset = 0;
}
public void WriteLiteral(uint value, int bitCount)
{
int shift = 24;
uint padded = value << ((32 - bitCount) - this.bitOffset);
while ((bitCount + this.bitOffset) >= 8)
{
byte current = (byte)(((padded >> shift) & 0xff) | this.buffer);
this.stream.WriteByte(current);
shift -= 8;
bitCount -= 8;
this.buffer = 0;
this.bitOffset = 0;
}
if (bitCount > 0)
{
this.buffer = (byte)(((padded >> shift) & 0xff) | this.buffer);
this.bitOffset += bitCount;
}
}
internal void WriteBoolean(bool value)
{
byte boolByte = value ? (byte)1 : (byte)0;
this.buffer = (byte)(((boolByte << (7 - this.bitOffset)) & 0xff) | this.buffer);
this.bitOffset++;
if (this.bitOffset == WordSize)
{
this.stream.WriteByte(this.buffer);
this.bitOffset = 0;
}
}
}

17
src/ImageSharp/Formats/Heif/Av1/Av1BlockModeInfo.cs

@ -0,0 +1,17 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal class Av1BlockModeInfo
{
public Av1BlockSize BlockSize { get; }
public Av1PredictionMode PredictionMode { get; }
public Av1PartitionType Partition { get; }
public int SegmentId { get; }
}

44
src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs

@ -0,0 +1,44 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal enum Av1BlockSize
{
Block4x4,
Block4x8,
Block8x4,
Block8x8,
Block8x16,
Block16x8,
Block16x16,
Block16x32,
Block32x16,
Block32x32,
Block32x64,
Block64x32,
Block64x64,
Block64x128,
Block128x64,
Block128x128,
Block4x16,
Block16x4,
Block8x32,
Block32x8,
Block16x64,
Block64x16,
BlockSizeSAll,
BlockSizeS = Block4x16,
BlockInvalid = 255,
BlockLargest = BlockSizeS - 1,
}
internal static class Av1BlockSizeExtensions
{
private static readonly int[] SizeWide = { 1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 1, 4, 2, 8, 4, 16 };
private static readonly int[] SizeHigh = { 1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 16, 8, 16, 32, 16, 32, 4, 1, 8, 2, 16, 4 };
public static int Get4x4WideCount(this Av1BlockSize blockSize) => SizeWide[(int)blockSize];
public static int Get4x4HighCount(this Av1BlockSize blockSize) => SizeHigh[(int)blockSize];
}

12
src/ImageSharp/Formats/Heif/Av1/Av1ColorFormat.cs

@ -0,0 +1,12 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal enum Av1ColorFormat
{
Yuv400,
Yuv420,
Yuv422,
Yuv444,
}

51
src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs

@ -0,0 +1,51 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal class Av1Decoder
{
public Av1Decoder()
{
this.FrameInfo = new ObuFrameHeader();
this.SequenceHeader = new ObuSequenceHeader();
this.TileInfo = new ObuTileInfo();
}
public bool SequenceHeaderDone { get; set; }
public bool ShowExistingFrame { get; set; }
public bool SeenFrameHeader { get; set; }
public ObuFrameHeader FrameInfo { get; }
public ObuSequenceHeader SequenceHeader { get; }
public ObuTileInfo TileInfo { get; }
public void Decode(Span<byte> buffer)
{
Av1BitStreamReader reader = new(buffer);
ObuReader.Read(ref reader, buffer.Length, this, false);
}
internal void DecodeTile(ref Av1BitStreamReader reader, int tileNum)
{
// TODO: Implement
}
internal void DecodeBlock(Av1BlockModeInfo blockMode, int rowIndex, int columnIndex)
{
int block4x4Width = blockMode.BlockSize.Get4x4WideCount();
int block4x4Height = blockMode.BlockSize.Get4x4HighCount();
}
internal void FinishDecodeTiles(ref Av1BitStreamReader reader, bool doCdef, bool doLoopRestoration)
{
// TODO: Implement
}
}

8
src/ImageSharp/Formats/Heif/Av1/Av1MainParseContext.cs

@ -0,0 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal class Av1MainParseContext
{
}

142
src/ImageSharp/Formats/Heif/Av1/Av1Math.cs

@ -0,0 +1,142 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal static class Av1Math
{
public static int MostSignificantBit(uint value)
{
int log = 0;
int i;
Guard.IsTrue(value != 0, nameof(value), "Must have al least 1 bit set");
for (i = 4; i >= 0; --i)
{
int shift = 1 << i;
uint x = value >> shift;
if (x != 0)
{
value = x;
log += shift;
}
}
return log;
}
public static uint Log2(uint n)
{
uint result = 0U;
while ((n >>= 1) > 0)
{
result++;
}
return result;
}
public static int Log2(int n)
{
int result = 0;
while ((n >>= 1) > 0)
{
result++;
}
return result;
}
public static uint FloorLog2(uint value)
{
uint s = 0;
while (value != 0U)
{
value >>= 1;
s++;
}
return s - 1;
}
public static uint CeilLog2(uint value)
{
if (value < 2)
{
return 0;
}
uint i = 1;
uint p = 2;
while (p < value)
{
i++;
p <<= 1;
}
return i;
}
public static uint Clip1(uint value, int bitDepth) =>
Clip3(0, (1U << bitDepth) - 1, value);
public static uint Clip3(uint x, uint y, uint z)
{
if (z < x)
{
return x;
}
if (z > y)
{
return y;
}
return z;
}
public static int Clip3(int x, int y, int z)
{
if (z < x)
{
return x;
}
if (z > y)
{
return y;
}
return z;
}
public static uint Round2(uint value, int n)
{
if (n == 0)
{
return value;
}
return (uint)((value + (1 << (n - 1))) >> n);
}
public static int Round2(int value, int n)
{
if (value < 0)
{
value = -value;
}
return (int)Round2((uint)value, n);
}
internal static int AlignPowerOf2(int value, int n)
{
int mask = (1 << n) - 1;
return (value + mask) & ~mask;
}
internal static int Clamp(int value, int low, int high)
=> value < low ? low : (value > high ? high : value);
}

62
src/ImageSharp/Formats/Heif/Av1/Av1PartitionType.cs

@ -0,0 +1,62 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal enum Av1PartitionType
{
/// <summary>
/// Not partitioned any further.
/// </summary>
None,
/// <summary>
/// Horizontally split in 2 partitions.
/// </summary>
Horizontal,
/// <summary>
/// Vertically split in 2 partitions.
/// </summary>
Vertical,
/// <summary>
/// 4 equally sized partitions.
/// </summary>
Split,
/// <summary>
/// Horizontal split and the top partition is split again.
/// </summary>
HorizontalA,
/// <summary>
/// Horizontal split and the bottom partition is split again.
/// </summary>
HorizontalB,
/// <summary>
/// Vertical split and the left partition is split again.
/// </summary>
VerticalA,
/// <summary>
/// Vertical split and the right partitino is split again.
/// </summary>
VerticalB,
/// <summary>
/// 4:1 horizontal partition.
/// </summary>
Horizontal4,
/// <summary>
/// 4:1 vertical partition.
/// </summary>
Vertical4,
/// <summary>
/// Invalid value.
/// </summary>
Invalid = 255
}

11
src/ImageSharp/Formats/Heif/Av1/Av1Plane.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal enum Av1Plane : int
{
Y = 0,
U = 1,
V = 2,
}

22
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuChromoSamplePosition.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuChromoSamplePosition : byte
{
/// <summary>
/// Unknown.
/// </summary>
Unknown = 0,
/// <summary>
/// Horizontally co-located with luma(0, 0) sample, between two vertical samples.
/// </summary>
Vertical = 1,
/// <summary>
/// Co-located with luma(0, 0) sample
/// </summary>
Colocated = 2,
}

52
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorConfig.cs

@ -0,0 +1,52 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuColorConfig
{
internal bool IsColorDescriptionPresent { get; set; }
internal int ChannelCount { get; set; }
internal bool Monochrome { get; set; }
internal ObuColorPrimaries ColorPrimaries { get; set; }
internal ObuTransferCharacteristics TransferCharacteristics { get; set; }
internal ObuMatrixCoefficients MatrixCoefficients { get; set; }
internal bool ColorRange { get; set; }
internal bool SubSamplingX { get; set; }
internal bool SubSamplingY { get; set; }
internal bool HasSeparateUvDelta { get; set; }
internal ObuChromoSamplePosition ChromaSamplePosition { get; set; }
internal int BitDepth { get; set; }
internal bool HasSeparateUvDeltaQ { get; set; }
public Av1ColorFormat GetColorFormat()
{
Av1ColorFormat format = Av1ColorFormat.Yuv400;
if (this.SubSamplingX && this.SubSamplingY)
{
format = Av1ColorFormat.Yuv420;
}
else if (this.SubSamplingX & !this.SubSamplingY)
{
format = Av1ColorFormat.Yuv422;
}
else if (!this.SubSamplingX && !this.SubSamplingY)
{
format = Av1ColorFormat.Yuv444;
}
return format;
}
}

21
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuColorPrimaries.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuColorPrimaries
{
None = 0,
Bt709 = 1,
Unspecified = 2,
Bt470M = 4,
Bt470BG = 5,
Bt601 = 6,
Smpte240 = 7,
GenericFilm = 8,
Bt2020 = 9,
Xyz = 10,
Smpte431 = 11,
Smpte432 = 12,
Ebu3213 = 22,
}

82
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuConstants.cs

@ -0,0 +1,82 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal static class ObuConstants
{
public const ObuSequenceProfile MaxSequenceProfile = ObuSequenceProfile.Professional;
public const int LevelBits = 5;
/// <summary>
/// Number of fractional bits for computing position in upscaling.
/// </summary>
public const int SuperResolutionScaleBits = 14;
public const int ScaleNumerator = -1;
/// <summary>
/// Number of reference frames that can be used for inter prediction.
/// </summary>
public const int ReferencesPerFrame = 7;
/// <summary>
/// Maximum area of a tile in units of luma samples.
/// </summary>
public const int MaxTileArea = 4096 * 2304;
/// <summary>
/// Maximum width of a tile in units of luma samples.
/// </summary>
public const int MaxTileWidth = 4096;
/// <summary>
/// Maximum number of tile columns.
/// </summary>
public const int MaxTileColumnCount = 64;
/// <summary>
/// Maximum number of tile rows.
/// </summary>
public const int MaxTileRowCount = 64;
/// <summary>
/// Number of frames that can be stored for future reference.
/// </summary>
public const int ReferenceFrameCount = 8;
/// <summary>
/// Value of 'PrimaryReferenceFrame' indicating that there is no primary reference frame.
/// </summary>
public const uint PrimaryReferenceFrameNone = 7;
public const int PimaryReferenceBits = -1;
/// <summary>
/// Number of segments allowed in segmentation map.
/// </summary>
public const int MaxSegmentCount = 8;
/// <summary>
/// Smallest denominator for upscaling ratio.
/// </summary>
public const int SuperResolutionScaleDenominatorMinimum = 9;
/// <summary>
/// Base 2 logarithm of maximum size of a superblock in luma samples.
/// </summary>
public const int MaxSuperBlockSizeLog2 = 7;
/// <summary>
/// Base 2 logarithm of smallest size of a mode info block.
/// </summary>
public const int ModeInfoSizeLog2 = 2;
public const int MaxQ = 255;
/// <summary>
/// Number of segmentation features.
/// </summary>
public const int SegmentationLevelMax = 8;
}

15
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuConstraintDirectionalEnhancementFilterParameters.cs

@ -0,0 +1,15 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuConstraintDirectionalEnhancementFilterParameters
{
public int BitCount { get; internal set; }
public int[] YStrength { get; internal set; } = new int[5];
public int[] UVStrength { get; internal set; } = new int[5];
public int Damping { get; internal set; }
}

13
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuDeltaLoopFilterParameters.cs

@ -0,0 +1,13 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuDeltaLoopFilterParameters
{
public bool IsPresent { get; internal set; }
public int Resolution { get; internal set; }
public bool Multi { get; internal set; }
}

11
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuDeltaQParameters.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuDeltaQParameters
{
public bool IsPresent { get; set; }
public int Resolution { get; set; }
}

9
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFilmGrainParameters.cs

@ -0,0 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuFilmGrainParameters
{
public bool ApplyGrain { get; set; }
}

89
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs

@ -0,0 +1,89 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuFrameHeader
{
public bool ForceIntegerMotionVector { get; set; }
public bool AllowIntraBlockCopy { get; set; }
public bool UseReferenceFrameMotionVectors { get; set; }
public bool AllowHighPrecisionMotionVector { get; set; }
public ObuTileInfo TilesInfo { get; set; } = new ObuTileInfo();
public bool CodedLossless { get; set; }
public bool[] LosslessArray { get; set; } = new bool[ObuConstants.MaxSegmentCount];
public ObuQuantizationParameters QuantizationParameters { get; set; } = new ObuQuantizationParameters();
public ObuSegmentationParameters SegmentationParameters { get; set; } = new ObuSegmentationParameters();
public bool AllLossless { get; set; }
public bool AllowWarpedMotion { get; set; }
public ObuReferenceMode ReferenceMode { get; set; }
public ObuFilmGrainParameters FilmGrainParameters { get; set; } = new ObuFilmGrainParameters();
public bool ReducedTransformSet { get; set; }
public ObuLoopFilterParameters LoopFilterParameters { get; set; } = new ObuLoopFilterParameters();
public ObuLoopRestorationParameters[] LoopRestorationParameters { get; set; } = new ObuLoopRestorationParameters[3];
public ObuConstraintDirectionalEnhancementFilterParameters CdefParameters { get; set; } = new ObuConstraintDirectionalEnhancementFilterParameters();
public int ModeInfoStride { get; set; }
public bool DisableFrameEndUpdateCdf { get; set; }
public ObuSkipModeParameters SkipModeParameters { get; set; } = new ObuSkipModeParameters();
public Av1TransformMode TransformMode { get; set; }
public ObuDeltaLoopFilterParameters DeltaLoopFilterParameters { get; set; } = new ObuDeltaLoopFilterParameters();
public ObuDeltaQParameters DeltaQParameters { get; set; } = new ObuDeltaQParameters();
internal ObuFrameSize FrameSize { get; set; } = new ObuFrameSize();
internal int ModeInfoColumnCount { get; set; }
internal int ModeInfoRowCount { get; set; }
internal bool ShowExistingFrame { get; set; }
internal ObuFrameType FrameType { get; set; }
internal bool[] ReferenceValid { get; set; } = new bool[ObuConstants.ReferenceFrameCount];
internal bool[] ReferenceOrderHint { get; set; } = new bool[ObuConstants.ReferenceFrameCount];
internal bool ShowFrame { get; set; }
internal bool ShowableFrame { get; set; }
internal bool ErrorResilientMode { get; set; }
internal bool AllowScreenContentTools { get; set; }
internal bool DisableCdfUpdate { get; set; }
internal uint CurrentFrameId { get; set; }
internal uint[] ReferenceFrameIndex { get; set; } = new uint[ObuConstants.ReferenceFrameCount];
internal uint OrderHint { get; set; }
internal uint PrimaryReferenceFrame { get; set; } = ObuConstants.PrimaryReferenceFrameNone;
internal uint RefreshFrameFlags { get; set; }
}

19
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameSize.cs

@ -0,0 +1,19 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuFrameSize
{
internal int FrameWidth { get; set; }
internal int FrameHeight { get; set; }
internal int SuperResolutionDenominator { get; set; }
internal int SuperResolutionUpscaledWidth { get; set; }
internal int RenderWidth { get; set; }
internal int RenderHeight { get; set; }
}

12
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameType.cs

@ -0,0 +1,12 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuFrameType
{
KeyFrame = 0,
InterFrame = 1,
IntraOnlyFrame = 2,
SwitchFrame = 3,
}

21
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuHeader.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuHeader
{
public int Size { get; set; }
public ObuType Type { get; set; }
public bool HasSize { get; set; }
public bool HasExtension { get; set; }
public int TemporalId { get; set; }
public int SpatialId { get; set; }
public int PayloadSize { get; set; }
}

9
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopFilterParameters.cs

@ -0,0 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuLoopFilterParameters
{
public int[] FilterLevel { get; internal set; } = new int[2];
}

9
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopRestorationParameters.cs

@ -0,0 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuLoopRestorationParameters
{
public ObuRestorationType FrameRestorationType { get; internal set; } = ObuRestorationType.RestoreNone;
}

22
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuMatrixCoefficients.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuMatrixCoefficients
{
Identity = 0,
Bt407 = 1,
Unspecified = 2,
Fcc = 4,
Bt470BG = 5,
Bt601 = 6,
Smpte240 = 7,
SmpteYCgCo = 8,
Bt2020NonConstantLuminance = 9,
Bt2020ConstantLuminance = 10,
Smpte2085 = 11,
ChromaticityDerivedNonConstantLuminance = 12,
ChromaticityDerivedConstandLuminance = 13,
Bt2100ICtCp = 14,
}

13
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuMetadataType.cs

@ -0,0 +1,13 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuMetadataType
{
ItutT35,
HdrCll,
HdrMdcv,
Scalability,
Timecode
}

17
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs

@ -0,0 +1,17 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuOperatingPoint
{
internal int OperatorIndex { get; set; }
internal int SequenceLevelIndex { get; set; }
internal int SequenceTier { get; set; }
internal bool IsDecoderModelPresent { get; set; }
internal bool IsInitialDisplayDelayPresent { get; set; }
}

15
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOrderHintInfo.cs

@ -0,0 +1,15 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuOrderHintInfo
{
public bool EnableOrderHint { get; internal set; }
internal bool EnableJointCompound { get; set; }
internal bool EnableReferenceFrameMotionVectors { get; set; }
internal int OrderHintBits { get; set; }
}

8
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuPartitionInfo.cs

@ -0,0 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuPartitionInfo
{
}

19
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuQuantizationParameters.cs

@ -0,0 +1,19 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuQuantizationParameters
{
public int BaseQIndex { get; set; }
public int[] QIndex { get; set; } = new int[ObuConstants.MaxSegmentCount];
public bool IsUsingQMatrix { get; internal set; }
public int[] DeltaQDc { get; internal set; } = new int[3];
public int[] DeltaQAc { get; internal set; } = new int[3];
public int[] QMatrix { get; internal set; } = new int[3];
}

1250
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs

File diff suppressed because it is too large

10
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReferenceMode.cs

@ -0,0 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuReferenceMode
{
ReferenceModeSelect,
SingleReference,
}

9
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuRestorationType.cs

@ -0,0 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuRestorationType
{
RestoreNone
}

16
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSegmentationLevelFeature.cs

@ -0,0 +1,16 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuSegmentationLevelFeature
{
AlternativeQuantizer,
AlternativeLoopFilterYVertical,
AlternativeLoopFilterYHorizontal,
AlternativeLoopFilterU,
AlternativeLoopFilterV,
ReferenceFrame,
Skip,
GlobalMotionVector,
}

15
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSegmentationParameters.cs

@ -0,0 +1,15 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuSegmentationParameters
{
public int[,] QMLevel { get; internal set; } = new int[3, ObuConstants.MaxSegmentCount];
public bool[,] FeatureEnabled { get; internal set; } = new bool[ObuConstants.MaxSegmentCount, ObuConstants.SegmentationLevelMax];
public bool SegmentationEnabled { get; internal set; }
public int[,] FeatureData { get; internal set; } = new int[ObuConstants.MaxSegmentCount, ObuConstants.SegmentationLevelMax];
}

71
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuSequenceHeader
{
internal bool IsStillPicture { get; set; }
internal bool IsReducedStillPictureHeader { get; set; }
internal ObuSequenceProfile SequenceProfile { get; set; }
internal ObuOperatingPoint[] OperatingPoint { get; set; } = new ObuOperatingPoint[1];
internal bool InitialDisplayDelayPresentFlag { get; set; }
internal bool DecoderModelInfoPresentFlag { get; set; }
internal object? TimingInfo { get; set; }
internal bool IsFrameIdNumbersPresent { get; set; }
internal int FrameWidthBits { get; set; }
internal int FrameHeightBits { get; set; }
internal int MaxFrameWidth { get; set; }
internal int MaxFrameHeight { get; set; }
internal bool Use128x128SuperBlock { get; set; }
internal Av1BlockSize SuperBlockSize { get; set; }
internal int ModeInfoSize { get; set; }
internal int SuperBlockSizeLog2 { get; set; }
internal int FilterIntraLevel { get; set; }
internal bool EnableIntraEdgeFilter { get; set; }
internal ObuOrderHintInfo OrderHintInfo { get; set; } = new ObuOrderHintInfo();
internal bool EnableInterIntraCompound { get; set; }
internal bool EnableMaskedCompound { get; set; }
internal bool EnableWarpedMotion { get; set; }
internal bool EnableDualFilter { get; set; }
internal int SequenceForceIntegerMotionVector { get; set; }
internal int SequenceForceScreenContentTools { get; set; }
internal bool EnableSuperResolution { get; set; }
internal int CdefLevel { get; set; }
internal bool EnableRestoration { get; set; }
internal ObuColorConfig ColorConfig { get; set; } = new ObuColorConfig();
internal bool AreFilmGrainingParametersPresent { get; set; }
internal int FrameIdLength { get; set; }
internal int DeltaFrameIdLength { get; set; }
}

11
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceProfile.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuSequenceProfile : uint
{
Main = 0,
High = 1,
Professional = 2,
}

11
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSkipModeParameters.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuSkipModeParameters
{
public bool SkipModeAllowed { get; set; }
public bool SkipModeFlag { get; internal set; }
}

39
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuTileInfo.cs

@ -0,0 +1,39 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuTileInfo
{
internal int MaxTileWidthSuperBlock { get; set; }
internal int MaxTileHeightSuperBlock { get; set; }
internal int MinLog2TileColumnCount { get; set; }
internal int MaxLog2TileColumnCount { get; set; }
internal int MaxLog2TileRowCount { get; set; }
internal int MinLog2TileCount { get; set; }
public bool HasUniformTileSpacing { get; set; }
internal int TileColumnCountLog2 { get; set; }
internal int TileColumnCount { get; set; }
internal int[] TileColumnStartModeInfo { get; set; } = new int[ObuConstants.MaxTileRowCount + 1];
internal int MinLog2TileRowCount { get; set; }
internal int TileRowCountLog2 { get; set; }
internal int[] TileRowStartModeInfo { get; set; } = new int[ObuConstants.MaxTileColumnCount + 1];
internal int TileRowCount { get; set; }
internal uint ContextUpdateTileId { get; set; }
internal int TileSizeBytes { get; set; }
}

25
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuTransferCharacteristics.cs

@ -0,0 +1,25 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuTransferCharacteristics
{
Bt709 = 1,
Unspecified = 2,
Bt470M = 4,
Bt470BG = 5,
Bt601 = 6,
Smpte240 = 7,
Linear = 8,
Log100 = 9,
Log100Sqrt10 = 10,
Iec61966 = 11,
Bt1361 = 12,
Srgb = 13,
Bt202010Bit = 14,
Bt202012Bit = 15,
Smpte2084 = 16,
Smpte248 = 17,
Hlg = 18,
}

18
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuType.cs

@ -0,0 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal enum ObuType
{
None = 0,
SequenceHeader = 1,
TemporalDelimiter = 2,
FrameHeader = 3,
RedundantFrameHeader = 7,
TileGroup = 4,
Metadata = 5,
Frame = 6,
TileList = 8,
Padding = 15,
}

26
src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionMode.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
// Inter modes are not defined here, as they do not apply to pictures.
internal enum Av1PredictionMode
{
DC,
Vertical,
Horizontal,
Directional45Degrees,
Directional135Degrees,
Directional113Degrees,
Directional157Degrees,
Directional203Degrees,
Directional67Degrees,
Smooth,
SmoothVertical,
SmoothHorizontal,
Paeth,
IntraModeStart = DC,
IntraModeEnd = Paeth + 1,
IntraModes = Paeth,
IntraInvalid = 25,
}

73
src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseQuantizer.cs

@ -0,0 +1,73 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
internal class Av1InverseQuantizer
{
public static int InverseQuantize(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, ObuPartitionInfo part, Av1BlockModeInfo mode, int[] level, int[] qCoefficients, Av1TransformMode txType, Av1TransformSize txSize, Av1Plane plane)
{
Av1ScanOrder scanOrder = Av1ScanOrderConstants.GetScanOrder(txSize, txType);
short[] scanIndices = scanOrder.Scan;
int maxValue = (1 << (7 + sequenceHeader.ColorConfig.BitDepth)) - 1;
int minValue = -(1 << (7 + sequenceHeader.ColorConfig.BitDepth));
bool usingQuantizationMatrix = frameHeader.QuantizationParameters.IsUsingQMatrix;
bool lossless = frameHeader.LosslessArray[mode.SegmentId];
short[] dequant = []; // Get from DecModCtx
int qmLevel = (lossless || !usingQuantizationMatrix) ? Av1ScanOrderConstants.QuantizationMatrixLevelCount - 1 : frameHeader.QuantizationParameters.QMatrix[(int)plane];
byte[] iqMatrix = []; // txType.Is2dTransform() ? Get from DecModCtx
int shift = txSize.GetScale();
int coefficientCount = level[0];
Span<int> levelSpan = level.AsSpan(1);
int lev = levelSpan[0];
int qCoefficient;
if (lev != 0)
{
int pos = scanIndices[0];
qCoefficient = (int)(((long)Math.Abs(lev) * GetDequantizationValue(dequant[0], pos, iqMatrix)) & 0xffffff);
qCoefficient >>= shift;
if (lev < 0)
{
qCoefficient = -qCoefficient;
}
qCoefficients[0] = Av1Math.Clamp(qCoefficient, minValue, maxValue);
}
for (int i = 1; i < coefficientCount; i++)
{
lev = levelSpan[i];
if (lev != 0)
{
int pos = scanIndices[i];
qCoefficient = (int)(((long)Math.Abs(lev) * GetDequantizationValue(dequant[1], pos, iqMatrix)) & 0xffffff);
qCoefficient >>= shift;
if (lev < 0)
{
qCoefficient = -qCoefficient;
}
qCoefficients[pos] = Av1Math.Clamp(qCoefficient, minValue, maxValue);
}
}
return coefficientCount;
}
private static int GetDequantizationValue(short dequant, int coefficientIndex, byte[] iqMatrix)
{
int dqv = dequant;
if (iqMatrix != null)
{
dqv = ((iqMatrix[coefficientIndex] * dqv) + (1 << (Av1ScanOrderConstants.QuantizationMatrixLevelBitCount - 1))) >> Av1ScanOrderConstants.QuantizationMatrixLevelBitCount;
}
return dqv;
}
}

148
src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransform.cs

@ -0,0 +1,148 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
internal static class Av1InverseTransform
{
public static readonly int[,] AcQLookup = new int[3, 256]
{
{
4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101,
102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138,
140, 142, 144, 146, 148, 150, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179, 182, 185, 188,
191, 194, 197, 200, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255, 260,
265, 270, 275, 280, 285, 290, 295, 300, 305, 311, 317, 323, 329, 335, 341, 347, 353, 359, 366,
373, 380, 387, 394, 401, 408, 416, 424, 432, 440, 448, 456, 465, 474, 483, 492, 501, 510, 520,
530, 540, 550, 560, 571, 582, 593, 604, 615, 627, 639, 651, 663, 676, 689, 702, 715, 729, 743,
757, 771, 786, 801, 816, 832, 848, 864, 881, 898, 915, 933, 951, 969, 988, 1007, 1026, 1046, 1066,
1087, 1108, 1129, 1151, 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343, 1369, 1396, 1423, 1451, 1479, 1508, 1537,
1567, 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
},
{
4, 9, 11, 13, 16, 18, 21, 24, 27, 30, 33, 37, 40, 44, 48, 51, 55, 59, 63,
67, 71, 75, 79, 83, 88, 92, 96, 100, 105, 109, 114, 118, 122, 127, 131, 136, 140, 145,
149, 154, 158, 163, 168, 172, 177, 181, 186, 190, 195, 199, 204, 208, 213, 217, 222, 226, 231,
235, 240, 244, 249, 253, 258, 262, 267, 271, 275, 280, 284, 289, 293, 297, 302, 306, 311, 315,
319, 324, 328, 332, 337, 341, 345, 349, 354, 358, 362, 367, 371, 375, 379, 384, 388, 392, 396,
401, 409, 417, 425, 433, 441, 449, 458, 466, 474, 482, 490, 498, 506, 514, 523, 531, 539, 547,
555, 563, 571, 579, 588, 596, 604, 616, 628, 640, 652, 664, 676, 688, 700, 713, 725, 737, 749,
761, 773, 785, 797, 809, 825, 841, 857, 873, 889, 905, 922, 938, 954, 970, 986, 1002, 1018, 1038,
1058, 1078, 1098, 1118, 1138, 1158, 1178, 1198, 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386, 1411, 1435, 1463,
1491, 1519, 1547, 1575, 1603, 1631, 1663, 1695, 1727, 1759, 1791, 1823, 1859, 1895, 1931, 1967, 2003, 2039, 2079,
2119, 2159, 2199, 2239, 2283, 2327, 2371, 2415, 2459, 2507, 2555, 2603, 2651, 2703, 2755, 2807, 2859, 2915, 2971,
3027, 3083, 3143, 3203, 3263, 3327, 3391, 3455, 3523, 3591, 3659, 3731, 3803, 3876, 3952, 4028, 4104, 4184, 4264,
4348, 4432, 4516, 4604, 4692, 4784, 4876, 4972, 5068, 5168, 5268, 5372, 5476, 5584, 5692, 5804, 5916, 6032, 6148,
6268, 6388, 6512, 6640, 6768, 6900, 7036, 7172, 7312,
},
{
4, 13, 19, 27, 35, 44, 54, 64, 75, 87, 99, 112, 126, 139, 154, 168,
183, 199, 214, 230, 247, 263, 280, 297, 314, 331, 349, 366, 384, 402, 420, 438,
456, 475, 493, 511, 530, 548, 567, 586, 604, 623, 642, 660, 679, 698, 716, 735,
753, 772, 791, 809, 828, 846, 865, 884, 902, 920, 939, 957, 976, 994, 1012, 1030,
1049, 1067, 1085, 1103, 1121, 1139, 1157, 1175, 1193, 1211, 1229, 1246, 1264, 1282, 1299, 1317,
1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457, 1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595,
1627, 1660, 1693, 1725, 1758, 1791, 1824, 1856, 1889, 1922, 1954, 1987, 2020, 2052, 2085, 2118,
2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378, 2411, 2459, 2508, 2556, 2605, 2653, 2701, 2750,
2798, 2847, 2895, 2943, 2992, 3040, 3088, 3137, 3185, 3234, 3298, 3362, 3426, 3491, 3555, 3619,
3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149, 4230, 4310, 4390, 4470, 4550, 4631, 4711, 4791,
4871, 4967, 5064, 5160, 5256, 5352, 5448, 5544, 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410,
6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435, 7579, 7723, 7867, 8011, 8155, 8315, 8475, 8635,
8795, 8956, 9132, 9308, 9484, 9660, 9836, 10028, 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661,
11885, 12109, 12333, 12573, 12813, 13053, 13309, 13565, 13821, 14093, 14365, 14637, 14925, 15213, 15502, 15806,
16110, 16414, 16734, 17054, 17390, 17726, 18062, 18414, 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486,
21902, 22334, 22766, 23214, 23662, 24126, 24590, 25070, 25551, 26047, 26559, 27071, 27599, 28143, 28687, 29247,
}
};
private static readonly int[,] DcQLookup = new int[3, 256]
{
{
4, 8, 8, 9, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23,
24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40,
41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 53, 54, 55, 56, 57,
57, 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 70, 71, 72, 73,
74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82, 83, 84, 85, 85, 87, 88, 90, 92,
93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 113, 114, 116, 117, 118, 120, 121,
123, 125, 127, 129, 131, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 161, 164,
166, 169, 172, 174, 177, 180, 182, 185, 187, 190, 192, 195, 199, 202, 205, 208, 211, 214, 217, 220,
223, 226, 230, 233, 237, 240, 243, 247, 250, 253, 257, 261, 265, 269, 272, 276, 280, 284, 288, 292,
296, 300, 304, 309, 313, 317, 322, 326, 330, 335, 340, 344, 349, 354, 359, 364, 369, 374, 379, 384,
389, 395, 400, 406, 411, 417, 423, 429, 435, 441, 447, 454, 461, 467, 475, 482, 489, 497, 505, 513,
522, 530, 539, 549, 559, 569, 579, 590, 602, 614, 626, 640, 654, 668, 684, 700, 717, 736, 755, 775,
796, 819, 843, 869, 896, 925, 955, 988, 1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336,
},
{
4, 9, 10, 13, 15, 17, 20, 22, 25, 28, 31, 34, 37, 40, 43, 47, 50, 53, 57,
60, 64, 68, 71, 75, 78, 82, 86, 90, 93, 97, 101, 105, 109, 113, 116, 120, 124, 128,
132, 136, 140, 143, 147, 151, 155, 159, 163, 166, 170, 174, 178, 182, 185, 189, 193, 197, 200,
204, 208, 212, 215, 219, 223, 226, 230, 233, 237, 241, 244, 248, 251, 255, 259, 262, 266, 269,
273, 276, 280, 283, 287, 290, 293, 297, 300, 304, 307, 310, 314, 317, 321, 324, 327, 331, 334,
337, 343, 350, 356, 362, 369, 375, 381, 387, 394, 400, 406, 412, 418, 424, 430, 436, 442, 448,
454, 460, 466, 472, 478, 484, 490, 499, 507, 516, 525, 533, 542, 550, 559, 567, 576, 584, 592,
601, 609, 617, 625, 634, 644, 655, 666, 676, 687, 698, 708, 718, 729, 739, 749, 759, 770, 782,
795, 807, 819, 831, 844, 856, 868, 880, 891, 906, 920, 933, 947, 961, 975, 988, 1001, 1015, 1030,
1045, 1061, 1076, 1090, 1105, 1120, 1137, 1153, 1170, 1186, 1202, 1218, 1236, 1253, 1271, 1288, 1306, 1323, 1342,
1361, 1379, 1398, 1416, 1436, 1456, 1476, 1496, 1516, 1537, 1559, 1580, 1601, 1624, 1647, 1670, 1692, 1717, 1741,
1766, 1791, 1817, 1844, 1871, 1900, 1929, 1958, 1990, 2021, 2054, 2088, 2123, 2159, 2197, 2236, 2276, 2319, 2363,
2410, 2458, 2508, 2561, 2616, 2675, 2737, 2802, 2871, 2944, 3020, 3102, 3188, 3280, 3375, 3478, 3586, 3702, 3823,
3953, 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347,
},
{
4, 12, 18, 25, 33, 41, 50, 60, 70, 80, 91, 103, 115, 127, 140, 153,
166, 180, 194, 208, 222, 237, 251, 266, 281, 296, 312, 327, 343, 358, 374, 390,
405, 421, 437, 453, 469, 484, 500, 516, 532, 548, 564, 580, 596, 611, 627, 643,
659, 674, 690, 706, 721, 737, 752, 768, 783, 798, 814, 829, 844, 859, 874, 889,
904, 919, 934, 949, 964, 978, 993, 1008, 1022, 1037, 1051, 1065, 1080, 1094, 1108, 1122,
1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234, 1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342,
1368, 1393, 1419, 1444, 1469, 1494, 1519, 1544, 1569, 1594, 1618, 1643, 1668, 1692, 1717, 1741,
1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933, 1957, 1992, 2027, 2061, 2096, 2130, 2165, 2199,
2233, 2267, 2300, 2334, 2367, 2400, 2434, 2467, 2499, 2532, 2575, 2618, 2661, 2704, 2746, 2788,
2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127, 3177, 3226, 3275, 3324, 3373, 3421, 3469, 3517,
3565, 3621, 3677, 3733, 3788, 3843, 3897, 3951, 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420,
4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942, 5013, 5083, 5153, 5222, 5291, 5367, 5442, 5517,
5591, 5665, 5745, 5825, 5905, 5984, 6063, 6149, 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867,
6966, 7064, 7163, 7269, 7376, 7483, 7599, 7715, 7832, 7958, 8085, 8214, 8352, 8492, 8635, 8788,
8945, 9104, 9275, 9450, 9639, 9832, 10031, 10245, 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409,
12750, 13118, 13501, 13913, 14343, 14807, 15290, 15812, 16356, 16943, 17575, 18237, 18949, 19718, 20521, 21387,
}
};
public static int GetDcQuantization(int qIndex, int delta, Av1BitDepth bitDepth)
=> DcQLookup[(int)bitDepth, Av1Math.Clip3(0, 255, qIndex + delta)];
public static int GetAcQuantization(int qIndex, int delta, Av1BitDepth bitDepth)
=> AcQLookup[(int)bitDepth, Av1Math.Clip3(0, 255, qIndex + delta)];
public static int GetQzbinFactor(int q, Av1BitDepth bitDepth)
{
int quant = GetDcQuantization(q, 0, bitDepth);
// Bit hack to get to:
// EightBit => 148
// TenBit => 592
// TwelveBit => 2368
int shift = (int)bitDepth << 1;
int threshold = (1 << shift) * 148;
return q == 0 ? 64 : (quant < threshold ? 84 : 80);
}
public static void InvertQuantization(out int quantization, out int shift, int d)
{
uint t;
int l, m;
t = (uint)d;
for (l = 0; t > 1; l++)
{
t >>= 1;
}
m = 1 + ((1 << (16 + l)) / d);
quantization = m - (1 << 16);
shift = 1 << (16 - l);
}
}

27
src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs

@ -0,0 +1,27 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal readonly struct Av1ScanOrder
{
public Av1ScanOrder(short[]? scan)
{
this.Scan = scan ?? [];
this.IScan = [];
this.Neighbors = [];
}
public Av1ScanOrder(short[] scan, short[] iscan, short[] neighbors)
{
this.Scan = scan;
this.IScan = iscan;
this.Neighbors = neighbors;
}
public short[] Scan { get; }
public short[] IScan { get; }
public short[] Neighbors { get; }
}

75
src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs

@ -0,0 +1,75 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal static class Av1ScanOrderConstants
{
public const int QuantizationMatrixLevelBitCount = 4;
public const int QuantizationMatrixLevelCount = 1 << QuantizationMatrixLevelBitCount;
private static readonly Av1ScanOrder[][] ScanOrders =
[
// Transform size 4x4
[
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(DefaultScan4x4),
new Av1ScanOrder(MatrixRowScan4x4),
new Av1ScanOrder(MatrixColumnScan4x4),
new Av1ScanOrder(MatrixRowScan4x4),
new Av1ScanOrder(MatrixColumnScan4x4),
new Av1ScanOrder(MatrixRowScan4x4),
new Av1ScanOrder(MatrixColumnScan4x4),
],
// Transform size 8x8
[
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(DefaultScan8x8),
new Av1ScanOrder(MatrixRowScan8x8),
new Av1ScanOrder(MatrixColumnScan8x8),
new Av1ScanOrder(MatrixRowScan8x8),
new Av1ScanOrder(MatrixColumnScan8x8),
new Av1ScanOrder(MatrixRowScan8x8),
new Av1ScanOrder(MatrixColumnScan8x8),
],
];
private static readonly short[] DefaultScan4x4 = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
private static readonly short[] MatrixColumnScan4x4 = [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15];
private static readonly short[] MatrixRowScan4x4 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
private static readonly short[] DefaultScan8x8 = [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 short[] MatrixColumnScan8x8 = [0, 8, 16, 24, 32, 40, 48, 56, 1, 9, 17, 25, 33, 41, 49, 57, 2, 10, 18, 26, 34, 42,
50, 58, 3, 11, 19, 27, 35, 43, 51, 59, 4, 12, 20, 28, 36, 44, 52, 60, 5, 13, 21, 29,
37, 45, 53, 61, 6, 14, 22, 30, 38, 46, 54, 62, 7, 15, 23, 31, 39, 47, 55, 63];
private static readonly short[] MatrixRowScan8x8 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63];
public static Av1ScanOrder GetScanOrder(Av1TransformSize txSize, Av1TransformMode txMode)
=> ScanOrders[(int)txSize][(int)txMode];
}

11
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformMode.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal enum Av1TransformMode : byte
{
Only4x4 = 0,
Largest = 1,
Select = 2,
}

30
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSize.cs

@ -0,0 +1,30 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
internal enum Av1TransformSize : byte
{
Size4x4,
Size8x8,
Size16x16,
Size32x32,
Size64x64,
Size4x8,
Size8x4,
Size8x16,
Size16x8,
Size16x32,
Size32x16,
Size32x64,
Size64x32,
Size4x16,
Size16x4,
Size8x32,
Size32x8,
Size16x64,
Size64x16,
AllSizes,
SquareSizes = Size4x8,
Invalid = 255,
}

16
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs

@ -0,0 +1,16 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
internal static class Av1TransformSizeExtensions
{
private static readonly int[] Size2d = [
16, 64, 256, 1024, 4096, 32, 32, 128, 128, 512, 512, 2048, 2048, 64, 64, 256, 256, 1024, 1024];
public static int GetScale(this Av1TransformSize size)
{
int pels = Size2d[(int)size];
return (pels > 1024) ? 2 : (pels > 256) ? 1 : 0;
}
}

49
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType.cs

@ -0,0 +1,49 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal enum Av1TransformType : byte
{
/// <summary>
/// DCT in both horizontal and vertical.
/// </summary>
DctDct,
/// <summary>
/// ADST in vertical, DCT in horizontal.
/// </summary>
AdstDct,
/// <summary>
/// DCT in vertical, ADST in horizontal.
/// </summary>
DctAdst,
/// <summary>
/// ADST in both directions.
/// </summary>
AdstAdst,
FlipAdstDct,
DctFlipAdst,
FlipAdstFlipAdst,
AdstFlipAdst,
FlipAdstAdst,
Identity,
VerticalDct,
HorizontalDct,
VerticalAdst,
HorizontalAdst,
VerticalFlipAdst,
HorizontalFlipAdst,
/// <summary>
/// Number of Transform types.
/// </summary>
TransformTypes,
/// <summary>
/// Invalid value.
/// </summary>
Invalid,
}

9
src/ImageSharp/Formats/Heif/Heif4CharCode.cs

@ -249,12 +249,17 @@ public enum Heif4CharCode : uint
Free = 0x66726565U,
/// <summary>
/// ICC Color Profile.
/// Color profile.
/// </summary>
nclx = 0x6E636C78U,
/// <summary>
/// ICC Color profile.
/// </summary>
RICC = 0x72494343U,
/// <summary>
/// ICC Color Profile.
/// ICC Color profile.
/// </summary>
Prof = 0x70726F66U,

5
src/ImageSharp/Formats/Heif/Heif4CharCode.tt

@ -54,8 +54,9 @@
"pict", "Picture handler type",
"uuid", "Unique Identifier",
"free", "Free space",
"rICC", "ICC Color Profile",
"prof", "ICC Color Profile",
"nclx", "Color profile",
"rICC", "ICC Color profile",
"prof", "ICC Color profile",
};
#>

3
src/ImageSharp/Formats/Heif/HeifDecoderCore.cs

@ -4,7 +4,8 @@
using System.Buffers;
using System.Buffers.Binary;
using System.Text;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Formats.Heif.Av1;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;

86
tests/ImageSharp.Tests/Formats/Heif/Av1/Av1BitStreamTests.cs

@ -0,0 +1,86 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
using SixLabors.ImageSharp.Formats.Heif.Av1;
namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
[Trait("Format", "Avif")]
public class Av1BitsStreamTests
{
[Theory]
[InlineData(42, new bool[] { false, false, true, false, true, false, true, false })]
[InlineData(52, new bool[] { false, false, true, true, false, true, false, false })]
public void ReadAsBoolean(byte value, bool[] bits)
{
int bitCount = bits.Length;
byte[] buffer = new byte[8];
buffer[0] = value;
Av1BitStreamReader reader = new(buffer);
bool[] actual = new bool[bitCount];
for (int i = 0; i < bitCount; i++)
{
actual[i] = reader.ReadBoolean();
}
Assert.Equal(bits, actual);
}
[Theory]
[InlineData(6, 4)]
[InlineData(42, 8)]
[InlineData(52, 8)]
[InlineData(4050, 16)]
public void ReadAsLiteral(uint expected, int bitCount)
{
byte[] buffer = new byte[8];
BinaryPrimitives.WriteUInt32BigEndian(buffer, expected << (32 - bitCount));
Av1BitStreamReader reader = new(buffer);
uint actual = reader.ReadLiteral(bitCount);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(new bool[] { false, false, true, false, true, false, true, false })]
[InlineData(new bool[] { false, true, false, true })]
public void WriteAsBoolean(bool[] booleans)
{
using MemoryStream stream = new(8);
Av1BitStreamWriter writer = new(stream);
for (int i = 0; i < booleans.Length; i++)
{
writer.WriteBoolean(booleans[i]);
}
writer.Flush();
// Read the written value back.
Av1BitStreamReader reader = new(stream.GetBuffer());
bool[] actual = new bool[booleans.Length];
for (int i = 0; i < booleans.Length; i++)
{
actual[i] = reader.ReadBoolean();
}
Assert.Equal(booleans, actual);
}
[Theory]
[InlineData(6, 4)]
[InlineData(42, 8)]
[InlineData(52, 8)]
[InlineData(4050, 16)]
public void WriteAsLiteral(uint value, int bitCount)
{
using MemoryStream stream = new(8);
Av1BitStreamWriter writer = new(stream);
writer.WriteLiteral(value, bitCount);
writer.Flush();
// Read the written value back.
Av1BitStreamReader reader = new(stream.GetBuffer());
uint actual = reader.ReadLiteral(bitCount);
Assert.Equal(value, actual);
}
}

32
tests/ImageSharp.Tests/Formats/Heif/Av1/ObuFrameHeaderTests.cs

@ -0,0 +1,32 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
namespace SixLabors.ImageSharp.Tests.Formats.Heif.Av1;
[Trait("Format", "Avif")]
public class ObuFrameHeaderTests
{
[Theory]
// [InlineData(TestImages.Heif.IrvineAvif, 0x0102, 0x000D, false)]
// [InlineData(TestImages.Heif.IrvineAvif, 0x0198, 0x6BD1, false)]
[InlineData(TestImages.Heif.XnConvert, 0x010E, 0x03CC, false)]
public void ReadFrameHeader(string filename, int fileOffset, int blockSize, bool isAnnexB)
{
// Assign
string filePath = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, filename);
byte[] content = File.ReadAllBytes(filePath);
Span<byte> span = content.AsSpan(fileOffset, blockSize);
Av1Decoder decoder = new();
// Act
decoder.Decode(span);
// Assert
Assert.True(decoder.SequenceHeaderDone);
Assert.False(decoder.SeenFrameHeader);
}
}

2
tests/ImageSharp.Tests/TestImages.cs

@ -1135,5 +1135,7 @@ public static class TestImages
// Downloaded from: https://github.com/AOMediaCodec/av1-avif/blob/master/testFiles/Microsoft/Irvine_CA.avif
public const string IrvineAvif = "Heif/Irvine_CA.avif";
public const string XnConvert = "Heif/jpeg444_xnconvert.avif";
}
}

3
tests/Images/Input/Heif/jpeg444_xnconvert.avif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:73c0521c669759df918cd59865537cd9cef3b7502ce3da825d8d24d9997e0e0d
size 1242
Loading…
Cancel
Save