Skip to content

Commit

Permalink
Skeleton code for pixel pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
ynse01 committed Aug 19, 2024
1 parent 0ff8911 commit 4f4ace4
Show file tree
Hide file tree
Showing 22 changed files with 1,310 additions and 145 deletions.
11 changes: 11 additions & 0 deletions src/ImageSharp/Formats/Heif/Av1/Av1BitDepthExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;

namespace SixLabors.ImageSharp.Formats.Heif.Av1;

internal static class Av1BitDepthExtensions
{
public static int GetBitCount(this Av1BitDepth bitDepth) => 8 + ((int)bitDepth << 1);
}
10 changes: 5 additions & 5 deletions src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,6 @@ internal static class Av1Constants
/// </summary>
public const int MaxAngleDelta = 3;

/// <summary>
/// Number of segments allowed in segmentation map.
/// </summary>
public const int MaxSegments = 8;

/// <summary>
/// Maximum number of color planes.
/// </summary>
Expand Down Expand Up @@ -173,4 +168,9 @@ internal static class Av1Constants
/// Log2 of number of values for ChromaFromLuma Alpha U and ChromaFromLuma Alpha V.
/// </summary>
public const int ChromaFromLumaAlphabetSizeLog2 = 4;

/// <summary>
/// Total number of Quantification Matrices sets stored.
/// </summary>
public const int QuantificationMatrixLevelCount = 4;
}
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Heif/Av1/Av1Decoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline;
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;

namespace SixLabors.ImageSharp.Formats.Heif.Av1;

Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Heif/Av1/Av1FrameBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public Av1FrameBuffer(Configuration configuration, ObuSequenceHeader sequenceHea
Av1ColorFormat colorFormat = sequenceHeader.ColorConfig.IsMonochrome ? Av1ColorFormat.Yuv400 : maxColorFormat;
this.MaxWidth = sequenceHeader.MaxFrameWidth;
this.MaxHeight = sequenceHeader.MaxFrameHeight;
this.BitDepth = (Av1BitDepth)sequenceHeader.ColorConfig.BitDepth;
this.BitDepth = sequenceHeader.ColorConfig.BitDepth;
int bitsPerPixel = this.BitDepth > Av1BitDepth.EightBit || is16BitPipeline ? 2 : 1;
this.ColorFormat = colorFormat;
this.BufferEnableMask = sequenceHeader.ColorConfig.IsMonochrome ? PictureBufferLumaMask : PictureBufferFullMask;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public bool IsMonochrome

public ObuChromoSamplePosition ChromaSamplePosition { get; set; }

public int BitDepth { get; set; }
public Av1BitDepth BitDepth { get; set; }

public Av1ColorFormat GetColorFormat()
{
Expand Down

This file was deleted.

27 changes: 7 additions & 20 deletions src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline.Quantification;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;

namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
Expand Down Expand Up @@ -78,7 +79,7 @@ public void ReadAll(ref Av1BitStreamReader reader, int dataSize, IAv1TileReader
case ObuType.SequenceHeader:
this.SequenceHeader = new();
ReadSequenceHeader(ref reader, this.SequenceHeader);
if (this.SequenceHeader.ColorConfig.BitDepth == 12)
if (this.SequenceHeader.ColorConfig.BitDepth == Av1BitDepth.TwelveBit)
{
// TODO: Initialize 12 bit predictors
}
Expand Down Expand Up @@ -503,7 +504,7 @@ private static ObuColorConfig ReadColorConfig(ref Av1BitStreamReader reader, Obu
break;
case ObuSequenceProfile.Professional:
default:
if (colorConfig.BitDepth == 12)
if (colorConfig.BitDepth == Av1BitDepth.TwelveBit)
{
colorConfig.SubSamplingX = reader.ReadBoolean();
if (colorConfig.SubSamplingX)
Expand Down Expand Up @@ -564,15 +565,15 @@ private static void ReadBitDepth(ref Av1BitStreamReader reader, ObuColorConfig c
bool hasHighBitDepth = reader.ReadBoolean();
if (sequenceHeader.SequenceProfile == ObuSequenceProfile.Professional && hasHighBitDepth)
{
colorConfig.BitDepth = reader.ReadBoolean() ? 12 : 10;
colorConfig.BitDepth = reader.ReadBoolean() ? Av1BitDepth.TwelveBit : Av1BitDepth.TenBit;
}
else if (sequenceHeader.SequenceProfile <= ObuSequenceProfile.Professional)
{
colorConfig.BitDepth = hasHighBitDepth ? 10 : 8;
colorConfig.BitDepth = hasHighBitDepth ? Av1BitDepth.TenBit : Av1BitDepth.EightBit;
}
else
{
colorConfig.BitDepth = 8;
colorConfig.BitDepth = Av1BitDepth.EightBit;
}
}

Expand Down Expand Up @@ -1091,7 +1092,7 @@ private void ReadUncompressedFrameHeader(ref Av1BitStreamReader reader)
frameHeader.SegmentationParameters.QMLevel[2] = new int[Av1Constants.MaxSegmentCount];
for (int segmentId = 0; segmentId < Av1Constants.MaxSegmentCount; segmentId++)
{
int qIndex = GetQIndex(frameHeader.SegmentationParameters, segmentId, frameHeader.QuantizationParameters.BaseQIndex);
int qIndex = QuantizationLookup.GetQIndex(frameHeader.SegmentationParameters, segmentId, frameHeader.QuantizationParameters.BaseQIndex);
frameHeader.QuantizationParameters.QIndex[segmentId] = qIndex;
frameHeader.LosslessArray[segmentId] = qIndex == 0 &&
frameHeader.QuantizationParameters.DeltaQDc[(int)Av1Plane.Y] == 0 &&
Expand Down Expand Up @@ -1151,20 +1152,6 @@ private void ReadUncompressedFrameHeader(ref Av1BitStreamReader reader)
private static bool IsSegmentationFeatureActive(ObuSegmentationParameters segmentationParameters, int segmentId, ObuSegmentationLevelFeature feature)
=> segmentationParameters.Enabled && segmentationParameters.IsFeatureActive(segmentId, feature);

private static int GetQIndex(ObuSegmentationParameters segmentationParameters, int segmentId, int baseQIndex)
{
if (IsSegmentationFeatureActive(segmentationParameters, segmentId, ObuSegmentationLevelFeature.AlternativeQuantizer))
{
int data = segmentationParameters.FeatureData[segmentId, (int)ObuSegmentationLevelFeature.AlternativeQuantizer];
int qIndex = baseQIndex + data;
return Av1Math.Clamp(qIndex, 0, Av1Constants.MaxQ);
}
else
{
return baseQIndex;
}
}

/// <summary>
/// 5.9.1. General frame header OBU syntax.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ private static void WriteColorConfig(ref Av1BitStreamWriter writer, ObuSequenceH
else
{
writer.WriteBoolean(colorConfig.ColorRange);
if (sequenceHeader.SequenceProfile == ObuSequenceProfile.Professional && colorConfig.BitDepth == 12)
if (sequenceHeader.SequenceProfile == ObuSequenceProfile.Professional && colorConfig.BitDepth == Av1BitDepth.TwelveBit)
{
writer.WriteBoolean(colorConfig.SubSamplingX);
if (colorConfig.SubSamplingX)
Expand All @@ -184,11 +184,11 @@ private static void WriteColorConfig(ref Av1BitStreamWriter writer, ObuSequenceH

private static void WriteBitDepth(ref Av1BitStreamWriter writer, ObuColorConfig colorConfig, ObuSequenceHeader sequenceHeader)
{
bool hasHighBitDepth = colorConfig.BitDepth > 8;
bool hasHighBitDepth = colorConfig.BitDepth > Av1BitDepth.EightBit;
writer.WriteBoolean(hasHighBitDepth);
if (sequenceHeader.SequenceProfile == ObuSequenceProfile.Professional && hasHighBitDepth)
{
writer.WriteBoolean(colorConfig.BitDepth == 12);
writer.WriteBoolean(colorConfig.BitDepth == Av1BitDepth.TwelveBit);
}
}

Expand Down
155 changes: 155 additions & 0 deletions src/ImageSharp/Formats/Heif/Av1/Pipeline/Av1FrameDecoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline.Quantification;
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;

namespace SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline;

internal class Av1FrameDecoder
{
private readonly ObuSequenceHeader sequenceHeader;
private readonly ObuFrameHeader frameHeader;
private readonly Av1FrameInfo frameInfo;
private readonly Av1InverseQuantizer inverseQuantizer;
private readonly DeQuant deQuants;

public Av1FrameDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, Av1FrameInfo frameInfo)
{
this.sequenceHeader = sequenceHeader;
this.frameHeader = frameHeader;
this.frameInfo = frameInfo;
this.inverseQuantizer = new(sequenceHeader, frameHeader);
this.deQuants = new();
}

public void DecodeFrame()
{
for (int column = 0; column < this.frameHeader.TilesInfo.TileColumnCount; column++)
{
this.DecodeFrameTiles(column);
}

bool doLoopFilterFlag = false;
bool doLoopRestoration = false;
bool doUpscale = false;
this.DecodeLoopFilterForFrame(doLoopFilterFlag);
if (doLoopRestoration)
{
// LoopRestorationSaveBoundaryLines(false);
}

// DecodeCdef();
// SuperResolutionUpscaling(doUpscale);
if (doLoopRestoration && doUpscale)
{
// LoopRestorationSaveBoundaryLines(true);
}

// DecodeLoopRestoration(doLoopRestoration);
// PadPicture();
}

private void DecodeFrameTiles(int tileColumn)
{
int tileRowCount = this.frameHeader.TilesInfo.TileRowCount;
int tileCount = tileRowCount * this.frameHeader.TilesInfo.TileColumnCount;
for (int row = 0; row < tileRowCount; row++)
{
int superblockRowTileStart = this.frameHeader.TilesInfo.TileRowStartModeInfo[row] << Av1Constants.ModeInfoSizeLog2 >>
this.sequenceHeader.SuperblockSizeLog2;
int superblockRow = row + superblockRowTileStart;

int modeInfoRow = superblockRow << this.sequenceHeader.SuperblockSizeLog2 >> Av1Constants.ModeInfoSizeLog2;

// EbColorConfig* color_config = &dec_mod_ctxt->seq_header->color_config;
// svt_cfl_init(&dec_mod_ctxt->cfl_ctx, color_config);
this.DecodeTileRow(row, tileColumn, modeInfoRow, superblockRow);
}
}

private void DecodeTileRow(int tileRow, int tileColumn, int modeInfoRow, int superblockRow)
{
int superblockModeInfoSizeLog2 = this.sequenceHeader.SuperblockSizeLog2 - Av1Constants.ModeInfoSizeLog2;
int superblockRowTileStart = this.frameHeader.TilesInfo.TileRowStartModeInfo[tileRow] << Av1Constants.ModeInfoSizeLog2 >>
this.sequenceHeader.SuperblockSizeLog2;

int superblockRowInTile = superblockRow - superblockRowTileStart;

ObuTileGroupHeader tileInfo = this.frameHeader.TilesInfo;
for (int modeInfoColumn = tileInfo.TileColumnStartModeInfo[tileColumn]; modeInfoColumn < tileInfo.TileColumnStartModeInfo[tileColumn + 1];
modeInfoColumn += this.sequenceHeader.SuperblockModeInfoSize)
{
int superblockColumn = modeInfoColumn << Av1Constants.ModeInfoSizeLog2 >> this.sequenceHeader.SuperblockSizeLog2;

Av1SuperblockInfo superblockInfo = this.frameInfo.GetSuperblock(new Point(superblockColumn, superblockRow));

Point modeInfoPosition = new Point(modeInfoColumn, modeInfoRow);
this.DecodeSuperblock(modeInfoPosition, superblockInfo);
}
}

private void DecodeSuperblock(Point modeInfoPosition, Av1SuperblockInfo superblockInfo)
{
this.inverseQuantizer.UpdateDequant(this.deQuants, superblockInfo);
DecodePartition(modeInfoPosition, superblockInfo);
}

private static void DecodePartition(Point modeInfoPosition, Av1SuperblockInfo superblockInfo)
{
Av1BlockModeInfo modeInfo = superblockInfo.GetModeInfo(modeInfoPosition);

for (int i = 0; i < superblockInfo.BlockCount; i++)
{
Point subPosition = modeInfo.PositionInSuperblock;
Av1BlockSize subSize = modeInfo.BlockSize;
Point globalPosition = new(modeInfoPosition.X, modeInfoPosition.Y);
globalPosition.Offset(subPosition);
Av1BlockDecoder.DecodeBlock(modeInfo, globalPosition, subSize, superblockInfo);
}
}

private void DecodeLoopFilterForFrame(bool doLoopFilterFlag)
{
if (!doLoopFilterFlag)
{
return;
}

int superblockSizeLog2 = this.sequenceHeader.SuperblockSizeLog2;
int pictureWidthInSuperblocks = Av1Math.DivideLog2Ceiling(this.frameHeader.FrameSize.FrameWidth, this.sequenceHeader.SuperblockSizeLog2);
int pictureHeightInSuperblocks = Av1Math.DivideLog2Ceiling(this.frameHeader.FrameSize.FrameHeight, this.sequenceHeader.SuperblockSizeLog2);

// Loop over a frame : tregger dec_loop_filter_sb for each SB
for (int superblockIndexY = 0; superblockIndexY < pictureHeightInSuperblocks; ++superblockIndexY)
{
for (int superblockIndexX = 0; superblockIndexX < pictureWidthInSuperblocks; ++superblockIndexX)
{
int superblockOriginX = superblockIndexX << superblockSizeLog2;
int superblockOriginY = superblockIndexY << superblockSizeLog2;
bool endOfRowFlag = superblockIndexX == pictureWidthInSuperblocks - 1;

Point superblockPoint = new(superblockOriginX, superblockOriginY);
Av1SuperblockInfo superblockInfo = this.frameInfo.GetSuperblock(superblockPoint);

// LF function for a SB
/*
DecodeLoopFilterForSuperblock(
superblockInfo,
this.frameHeader,
this.sequenceHeader,
reconstructionFrameBuffer,
loopFilterContext,
superblockOriginY >> 2,
superblockOriginX >> 2,
Av1Plane.Y,
3,
endOfRowFlag,
superblockInfo.SuperblockDeltaLoopFilter);
*/
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline.LoopFilter;

internal class Av1LoopFilterContext
{
}
Loading

0 comments on commit 4f4ace4

Please sign in to comment.