mirror of https://github.com/SixLabors/ImageSharp
8 changed files with 705 additions and 40 deletions
@ -0,0 +1,583 @@ |
|||
// 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 ObuWriter |
|||
{ |
|||
/// <summary>
|
|||
/// Encode a single frame into OBU's.
|
|||
/// </summary>
|
|||
public static void Write(Stream stream, IAv1TileDecoder decoder) |
|||
{ |
|||
MemoryStream bufferStream = new(100); |
|||
Av1BitStreamWriter writer = new(bufferStream); |
|||
WriteSequenceHeader(ref writer, decoder.SequenceHeader); |
|||
WriteObuHeaderAndSize(stream, ObuType.SequenceHeader, bufferStream.GetBuffer(), (int)bufferStream.Position); |
|||
|
|||
bufferStream.Position = 0; |
|||
WriteFrameHeader(ref writer, decoder, true); |
|||
WriteObuHeaderAndSize(stream, ObuType.FrameHeader, bufferStream.GetBuffer(), (int)bufferStream.Position); |
|||
|
|||
bufferStream.Position = 0; |
|||
WriteTileGroup(ref writer, decoder.TileInfo); |
|||
WriteObuHeaderAndSize(stream, ObuType.TileGroup, bufferStream.GetBuffer(), (int)bufferStream.Position); |
|||
} |
|||
|
|||
private static void WriteObuHeader(ref Av1BitStreamWriter writer, ObuType type) |
|||
{ |
|||
writer.WriteBoolean(false); // Forbidden bit
|
|||
writer.WriteLiteral((uint)type, 4); |
|||
writer.WriteBoolean(false); // Extension
|
|||
writer.WriteBoolean(true); // HasSize
|
|||
writer.WriteBoolean(false); // Reserved
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Read OBU header and size.
|
|||
/// </summary>
|
|||
private static void WriteObuHeaderAndSize(Stream stream, ObuType type, Span<byte> payload, int length) |
|||
{ |
|||
Av1BitStreamWriter writer = new(stream); |
|||
WriteObuHeader(ref writer, type); |
|||
_ = writer.WriteLittleEndianBytes128(length); |
|||
stream.Write(payload, 0, length); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Write trsainling bits to end on a byte boundary, these trailing bits start with a 1 and end with 0s.
|
|||
/// </summary>
|
|||
/// <remarks>Write an additional byte, if already byte aligned before.</remarks>
|
|||
private static void WriteTrailingBits(ref Av1BitStreamWriter writer) |
|||
{ |
|||
int bitsBeforeAlignment = 8 - (writer.BitPosition & 0x7); |
|||
writer.WriteLiteral(0, bitsBeforeAlignment); |
|||
} |
|||
|
|||
private static void AlignToByteBoundary(ref Av1BitStreamWriter writer) |
|||
{ |
|||
while ((writer.BitPosition & 0x7) > 0) |
|||
{ |
|||
writer.WriteBoolean(false); |
|||
} |
|||
} |
|||
|
|||
private static bool IsValidObuType(ObuType type) => type switch |
|||
{ |
|||
ObuType.SequenceHeader or ObuType.TemporalDelimiter or ObuType.FrameHeader or |
|||
ObuType.TileGroup or ObuType.Metadata or ObuType.Frame or ObuType.RedundantFrameHeader or |
|||
ObuType.TileList or ObuType.Padding => true, |
|||
_ => false, |
|||
}; |
|||
|
|||
private static void WriteSequenceHeader(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader) |
|||
{ |
|||
writer.WriteLiteral((uint)sequenceHeader.SequenceProfile, 3); |
|||
writer.WriteBoolean(true); // IsStillPicture
|
|||
writer.WriteBoolean(true); // IsReducedStillPicture
|
|||
writer.WriteLiteral((uint)sequenceHeader.OperatingPoint[0].SequenceLevelIndex, ObuConstants.LevelBits); |
|||
|
|||
// Frame width and Height
|
|||
writer.WriteLiteral((uint)sequenceHeader.FrameWidthBits - 1, 4); |
|||
writer.WriteLiteral((uint)sequenceHeader.FrameHeightBits - 1, 4); |
|||
writer.WriteLiteral((uint)sequenceHeader.MaxFrameWidth - 1, sequenceHeader.FrameWidthBits); |
|||
writer.WriteLiteral((uint)sequenceHeader.MaxFrameHeight - 1, sequenceHeader.FrameHeightBits); |
|||
|
|||
// Video related flags removed
|
|||
writer.WriteBoolean(sequenceHeader.Use128x128SuperBlock); |
|||
writer.WriteBoolean(sequenceHeader.EnableFilterIntra); |
|||
writer.WriteBoolean(sequenceHeader.EnableIntraEdgeFilter); |
|||
|
|||
// Video related flags removed
|
|||
writer.WriteBoolean(sequenceHeader.EnableSuperResolution); |
|||
writer.WriteBoolean(sequenceHeader.EnableCdef); |
|||
writer.WriteBoolean(sequenceHeader.EnableRestoration); |
|||
WriteColorConfig(ref writer, sequenceHeader); |
|||
writer.WriteBoolean(sequenceHeader.AreFilmGrainingParametersPresent); |
|||
WriteTrailingBits(ref writer); |
|||
} |
|||
|
|||
private static void WriteColorConfig(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader) |
|||
{ |
|||
ObuColorConfig colorConfig = new(); |
|||
WriteBitDepth(ref writer, colorConfig, sequenceHeader); |
|||
if (sequenceHeader.SequenceProfile != ObuSequenceProfile.High) |
|||
{ |
|||
writer.WriteBoolean(colorConfig.Monochrome); |
|||
} |
|||
|
|||
writer.WriteBoolean(false); // colorConfig.IsColorDescriptionPresent
|
|||
if (colorConfig.Monochrome) |
|||
{ |
|||
writer.WriteBoolean(colorConfig.ColorRange); |
|||
return; |
|||
} |
|||
else if ( |
|||
colorConfig.ColorPrimaries == ObuColorPrimaries.Bt709 && |
|||
colorConfig.TransferCharacteristics == ObuTransferCharacteristics.Srgb && |
|||
colorConfig.MatrixCoefficients == ObuMatrixCoefficients.Identity) |
|||
{ |
|||
colorConfig.ColorRange = true; |
|||
colorConfig.SubSamplingX = false; |
|||
colorConfig.SubSamplingY = false; |
|||
} |
|||
else |
|||
{ |
|||
writer.WriteBoolean(colorConfig.ColorRange); |
|||
if (sequenceHeader.SequenceProfile == ObuSequenceProfile.Professional && colorConfig.BitDepth == 12) |
|||
{ |
|||
writer.WriteBoolean(colorConfig.SubSamplingX); |
|||
if (colorConfig.SubSamplingX) |
|||
{ |
|||
writer.WriteBoolean(colorConfig.SubSamplingY); |
|||
} |
|||
} |
|||
|
|||
if (colorConfig.SubSamplingX && colorConfig.SubSamplingY) |
|||
{ |
|||
writer.WriteLiteral((uint)colorConfig.ChromaSamplePosition, 2); |
|||
} |
|||
} |
|||
|
|||
writer.WriteBoolean(colorConfig.HasSeparateUvDeltaQ); |
|||
} |
|||
|
|||
private static void WriteBitDepth(ref Av1BitStreamWriter writer, ObuColorConfig colorConfig, ObuSequenceHeader sequenceHeader) |
|||
{ |
|||
bool hasHighBitDepth = colorConfig.BitDepth > 8; |
|||
writer.WriteBoolean(hasHighBitDepth); |
|||
if (sequenceHeader.SequenceProfile == ObuSequenceProfile.Professional && hasHighBitDepth) |
|||
{ |
|||
writer.WriteBoolean(colorConfig.BitDepth == 12); |
|||
} |
|||
} |
|||
|
|||
private static void WriteSuperResolutionParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo) |
|||
{ |
|||
bool useSuperResolution = false; |
|||
if (sequenceHeader.EnableSuperResolution) |
|||
{ |
|||
writer.WriteBoolean(useSuperResolution); |
|||
} |
|||
|
|||
if (useSuperResolution) |
|||
{ |
|||
writer.WriteLiteral((uint)frameInfo.FrameSize.SuperResolutionDenominator - ObuConstants.SuperResolutionScaleDenominatorMinimum, ObuConstants.SuperResolutionScaleBits); |
|||
} |
|||
} |
|||
|
|||
private static void WriteRenderSize(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) |
|||
{ |
|||
bool renderSizeAndFrameSizeDifferent = false; |
|||
writer.WriteBoolean(false); |
|||
if (renderSizeAndFrameSizeDifferent) |
|||
{ |
|||
writer.WriteLiteral((uint)frameInfo.FrameSize.RenderWidth - 1, 16); |
|||
writer.WriteLiteral((uint)frameInfo.FrameSize.RenderHeight - 1, 16); |
|||
} |
|||
} |
|||
|
|||
private static void WriteFrameSizeWithReferences(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool frameSizeOverrideFlag) |
|||
{ |
|||
bool foundReference = false; |
|||
for (int i = 0; i < ObuConstants.ReferencesPerFrame; i++) |
|||
{ |
|||
writer.WriteBoolean(foundReference); |
|||
if (foundReference) |
|||
{ |
|||
// Take values over from reference frame
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!foundReference) |
|||
{ |
|||
WriteFrameSize(ref writer, sequenceHeader, frameInfo, frameSizeOverrideFlag); |
|||
WriteRenderSize(ref writer, frameInfo); |
|||
} |
|||
else |
|||
{ |
|||
WriteSuperResolutionParameters(ref writer, sequenceHeader, frameInfo); |
|||
} |
|||
} |
|||
|
|||
private static void WriteFrameSize(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool frameSizeOverrideFlag) |
|||
{ |
|||
if (frameSizeOverrideFlag) |
|||
{ |
|||
writer.WriteLiteral((uint)frameInfo.FrameSize.FrameWidth - 1, sequenceHeader.FrameWidthBits + 1); |
|||
writer.WriteLiteral((uint)frameInfo.FrameSize.FrameHeight - 1, sequenceHeader.FrameHeightBits + 1); |
|||
} |
|||
|
|||
WriteSuperResolutionParameters(ref writer, sequenceHeader, frameInfo); |
|||
} |
|||
|
|||
private static void WriteTileInfo(ref Av1BitStreamWriter writer, ObuTileInfo tileInfo) |
|||
{ |
|||
Guard.IsTrue(tileInfo.HasUniformTileSpacing, nameof(tileInfo.HasUniformTileSpacing), "NON uniform_tile_spacing_flag not supported yet."); |
|||
|
|||
writer.WriteBoolean(tileInfo.HasUniformTileSpacing); |
|||
if (tileInfo.HasUniformTileSpacing) |
|||
{ |
|||
for (int i = 0; i < tileInfo.TileColumnCountLog2; i++) |
|||
{ |
|||
writer.WriteBoolean(true); |
|||
} |
|||
|
|||
if (tileInfo.TileColumnCountLog2 < tileInfo.MaxLog2TileColumnCount) |
|||
{ |
|||
writer.WriteBoolean(false); |
|||
} |
|||
|
|||
for (int i = 0; i < tileInfo.TileRowCountLog2; i++) |
|||
{ |
|||
writer.WriteBoolean(true); |
|||
} |
|||
|
|||
if (tileInfo.TileRowCountLog2 < tileInfo.MaxLog2TileRowCount) |
|||
{ |
|||
writer.WriteBoolean(false); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
throw new NotImplementedException("NON uniform_tile_spacing_flag not supported yet."); |
|||
} |
|||
|
|||
if (tileInfo.TileColumnCountLog2 > 0 || tileInfo.TileRowCountLog2 > 0) |
|||
{ |
|||
writer.WriteLiteral(tileInfo.ContextUpdateTileId, tileInfo.TileRowCountLog2 + tileInfo.TileColumnCountLog2); |
|||
writer.WriteLiteral((uint)tileInfo.TileSizeBytes - 1, 2); |
|||
} |
|||
} |
|||
|
|||
private static void WriteUncompressedFrameHeader(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, int planesCount) |
|||
{ |
|||
uint previousFrameId = 0; |
|||
bool isIntraFrame = true; |
|||
int idLength = sequenceHeader.FrameIdLength - 1 + sequenceHeader.DeltaFrameIdLength - 2 + 3; |
|||
writer.WriteBoolean(frameInfo.DisableCdfUpdate); |
|||
if (frameInfo.AllowScreenContentTools) |
|||
{ |
|||
writer.WriteBoolean(frameInfo.AllowScreenContentTools); |
|||
} |
|||
|
|||
if (frameInfo.AllowScreenContentTools) |
|||
{ |
|||
if (sequenceHeader.SequenceForceIntegerMotionVector == 1) |
|||
{ |
|||
writer.WriteBoolean(frameInfo.ForceIntegerMotionVector); |
|||
} |
|||
} |
|||
|
|||
bool havePreviousFrameId = !(frameInfo.FrameType == ObuFrameType.KeyFrame && frameInfo.ShowFrame); |
|||
if (havePreviousFrameId) |
|||
{ |
|||
previousFrameId = frameInfo.CurrentFrameId; |
|||
} |
|||
|
|||
if (sequenceHeader.IsFrameIdNumbersPresent) |
|||
{ |
|||
writer.WriteLiteral(frameInfo.CurrentFrameId, idLength); |
|||
if (havePreviousFrameId) |
|||
{ |
|||
uint diffFrameId = (frameInfo.CurrentFrameId > previousFrameId) ? |
|||
frameInfo.CurrentFrameId - previousFrameId : |
|||
(uint)((1 << idLength) + (int)frameInfo.CurrentFrameId - previousFrameId); |
|||
if (frameInfo.CurrentFrameId == previousFrameId || diffFrameId >= 1 << (idLength - 1)) |
|||
{ |
|||
throw new ImageFormatException("Current frame ID cannot be same as previous Frame ID"); |
|||
} |
|||
} |
|||
|
|||
int diffLength = sequenceHeader.DeltaFrameIdLength; |
|||
for (int i = 0; i < ObuConstants.ReferenceFrameCount; i++) |
|||
{ |
|||
if (frameInfo.CurrentFrameId > (1U << diffLength)) |
|||
{ |
|||
if ((frameInfo.ReferenceFrameIndex[i] > frameInfo.CurrentFrameId) || |
|||
frameInfo.ReferenceFrameIndex[i] > (frameInfo.CurrentFrameId - (1 - diffLength))) |
|||
{ |
|||
frameInfo.ReferenceValid[i] = false; |
|||
} |
|||
} |
|||
else if (frameInfo.ReferenceFrameIndex[i] > frameInfo.CurrentFrameId && |
|||
frameInfo.ReferenceFrameIndex[i] < ((1 << idLength) + (frameInfo.CurrentFrameId - (1 << diffLength)))) |
|||
{ |
|||
frameInfo.ReferenceValid[i] = false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
writer.WriteLiteral(frameInfo.OrderHint, sequenceHeader.OrderHintInfo.OrderHintBits); |
|||
|
|||
if (!isIntraFrame && !frameInfo.ErrorResilientMode) |
|||
{ |
|||
writer.WriteLiteral(frameInfo.PrimaryReferenceFrame, ObuConstants.PimaryReferenceBits); |
|||
} |
|||
|
|||
// Skipping, as no decoder info model present
|
|||
frameInfo.AllowHighPrecisionMotionVector = false; |
|||
frameInfo.UseReferenceFrameMotionVectors = false; |
|||
frameInfo.AllowIntraBlockCopy = false; |
|||
if (frameInfo.FrameType != ObuFrameType.SwitchFrame && !(frameInfo.FrameType == ObuFrameType.KeyFrame && frameInfo.ShowFrame)) |
|||
{ |
|||
writer.WriteLiteral(frameInfo.RefreshFrameFlags, 8); |
|||
} |
|||
|
|||
if (isIntraFrame) |
|||
{ |
|||
WriteFrameSize(ref writer, sequenceHeader, frameInfo, false); |
|||
WriteRenderSize(ref writer, frameInfo); |
|||
if (frameInfo.AllowScreenContentTools && frameInfo.FrameSize.RenderWidth != 0) |
|||
{ |
|||
if (frameInfo.FrameSize.FrameWidth == frameInfo.FrameSize.SuperResolutionUpscaledWidth) |
|||
{ |
|||
writer.WriteBoolean(frameInfo.AllowIntraBlockCopy); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (frameInfo.PrimaryReferenceFrame == ObuConstants.PrimaryReferenceFrameNone) |
|||
{ |
|||
SetupPastIndependence(frameInfo); |
|||
} |
|||
|
|||
// GenerateNextReferenceFrameMap(sequenceHeader, frameInfo);
|
|||
WriteTileInfo(ref writer, frameInfo.TilesInfo); |
|||
WriteQuantizationParameters(ref writer, frameInfo.QuantizationParameters, sequenceHeader.ColorConfig, planesCount); |
|||
WriteSegmentationParameters(ref writer, sequenceHeader, frameInfo, planesCount); |
|||
WriteFrameDeltaQParameters(ref writer, frameInfo); |
|||
WriteFrameDeltaLoopFilterParameters(ref writer, frameInfo); |
|||
|
|||
WriteLoopFilterParameters(ref writer, sequenceHeader, frameInfo, planesCount); |
|||
WriteCdefParameters(ref writer, sequenceHeader, frameInfo, planesCount); |
|||
WriteLoopRestorationParameters(ref writer, sequenceHeader, frameInfo, planesCount); |
|||
WriteTransformMode(ref writer, frameInfo); |
|||
|
|||
// Not applicable for INTRA frames.
|
|||
// WriteFrameReferenceMode(ref writer, frameInfo.ReferenceMode, isIntraFrame);
|
|||
// WriteSkipModeParameters(ref writer, sequenceHeader, frameInfo, isIntraFrame, frameInfo.ReferenceMode);
|
|||
writer.WriteBoolean(frameInfo.ReducedTransformSet); |
|||
|
|||
// Not applicable for INTRA frames.
|
|||
// WriteGlobalMotionParameters(ref writer, sequenceHeader, frameInfo, isIntraFrame);
|
|||
WriteFilmGrainFilterParameters(ref writer, frameInfo.FilmGrainParameters); |
|||
} |
|||
|
|||
private static void SetupPastIndependence(ObuFrameHeader frameInfo) |
|||
{ |
|||
// TODO: Initialize the loop filter parameters.
|
|||
} |
|||
|
|||
private static bool IsSegmentationFeatureActive(ObuSegmentationParameters segmentationParameters, int segmentId, ObuSegmentationLevelFeature feature) |
|||
=> segmentationParameters.SegmentationEnabled && segmentationParameters.FeatureEnabled[segmentId, (int)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, ObuConstants.MaxQ); |
|||
} |
|||
else |
|||
{ |
|||
return baseQIndex; |
|||
} |
|||
} |
|||
|
|||
private static int WriteFrameHeader(ref Av1BitStreamWriter writer, IAv1TileDecoder decoder, bool writeTrailingBits) |
|||
{ |
|||
ObuSequenceHeader sequenceHeader = decoder.SequenceHeader; |
|||
ObuFrameHeader frameInfo = decoder.FrameInfo; |
|||
int planeCount = sequenceHeader.ColorConfig.Monochrome ? 1 : 3; |
|||
int startBitPosition = writer.BitPosition; |
|||
WriteUncompressedFrameHeader(ref writer, sequenceHeader, frameInfo, planeCount); |
|||
if (writeTrailingBits) |
|||
{ |
|||
WriteTrailingBits(ref writer); |
|||
} |
|||
|
|||
AlignToByteBoundary(ref writer); |
|||
|
|||
int endPosition = writer.BitPosition; |
|||
int headerBytes = (endPosition - startBitPosition) / 8; |
|||
return headerBytes; |
|||
} |
|||
|
|||
private static int WriteTileGroup(ref Av1BitStreamWriter writer, ObuTileInfo tileInfo) |
|||
{ |
|||
int tileCount = tileInfo.TileColumnCount * tileInfo.TileRowCount; |
|||
int startBitPosition = writer.BitPosition; |
|||
bool tileStartAndEndPresentFlag = tileCount != 0; |
|||
writer.WriteBoolean(tileStartAndEndPresentFlag); |
|||
|
|||
uint tileGroupStart = 0U; |
|||
uint tileGroupEnd = (uint)tileCount - 1U; |
|||
if (tileCount != 1) |
|||
{ |
|||
int tileBits = Av1Math.Log2(tileInfo.TileColumnCount) + Av1Math.Log2(tileInfo.TileRowCount); |
|||
writer.WriteLiteral(tileGroupStart, tileBits); |
|||
writer.WriteLiteral(tileGroupEnd, tileBits); |
|||
} |
|||
|
|||
AlignToByteBoundary(ref writer); |
|||
int endBitPosition = writer.BitPosition; |
|||
int headerBytes = (endBitPosition - startBitPosition) / 8; |
|||
return headerBytes; |
|||
} |
|||
|
|||
private static int WriteDeltaQ(ref Av1BitStreamWriter writer, int deltaQ) |
|||
{ |
|||
bool isCoded = deltaQ == 0; |
|||
writer.WriteBoolean(isCoded); |
|||
if (isCoded) |
|||
{ |
|||
writer.WriteSignedFromUnsigned(deltaQ, 7); |
|||
} |
|||
|
|||
return deltaQ; |
|||
} |
|||
|
|||
private static void WriteFrameDeltaQParameters(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) |
|||
{ |
|||
if (frameInfo.QuantizationParameters.BaseQIndex > 0) |
|||
{ |
|||
writer.WriteBoolean(frameInfo.DeltaQParameters.IsPresent); |
|||
} |
|||
|
|||
if (frameInfo.DeltaQParameters.IsPresent) |
|||
{ |
|||
writer.WriteLiteral((uint)frameInfo.DeltaQParameters.Resolution, 2); |
|||
} |
|||
} |
|||
|
|||
private static void WriteFrameDeltaLoopFilterParameters(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) |
|||
{ |
|||
if (frameInfo.DeltaQParameters.IsPresent) |
|||
{ |
|||
if (!frameInfo.AllowIntraBlockCopy) |
|||
{ |
|||
writer.WriteBoolean(frameInfo.DeltaLoopFilterParameters.IsPresent); |
|||
} |
|||
|
|||
if (frameInfo.DeltaLoopFilterParameters.IsPresent) |
|||
{ |
|||
writer.WriteLiteral((uint)frameInfo.DeltaLoopFilterParameters.Resolution, 2); |
|||
writer.WriteBoolean(frameInfo.DeltaLoopFilterParameters.Multi); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// See section 5.9.12.
|
|||
/// </summary>
|
|||
private static void WriteQuantizationParameters(ref Av1BitStreamWriter writer, ObuQuantizationParameters quantParams, ObuColorConfig colorInfo, int planesCount) |
|||
{ |
|||
writer.WriteLiteral((uint)quantParams.BaseQIndex, 8); |
|||
WriteDeltaQ(ref writer, quantParams.DeltaQDc[(int)Av1Plane.Y]); |
|||
if (planesCount > 1) |
|||
{ |
|||
bool areUvDeltaDifferent = false; |
|||
WriteDeltaQ(ref writer, quantParams.DeltaQDc[(int)Av1Plane.U]); |
|||
WriteDeltaQ(ref writer, quantParams.DeltaQAc[(int)Av1Plane.U]); |
|||
if (areUvDeltaDifferent) |
|||
{ |
|||
WriteDeltaQ(ref writer, quantParams.DeltaQDc[(int)Av1Plane.V]); |
|||
WriteDeltaQ(ref writer, quantParams.DeltaQAc[(int)Av1Plane.V]); |
|||
} |
|||
} |
|||
|
|||
writer.WriteBoolean(quantParams.IsUsingQMatrix); |
|||
if (quantParams.IsUsingQMatrix) |
|||
{ |
|||
writer.WriteLiteral((uint)quantParams.QMatrix[(int)Av1Plane.Y], 4); |
|||
writer.WriteLiteral((uint)quantParams.QMatrix[(int)Av1Plane.U], 4); |
|||
if (colorInfo.HasSeparateUvDeltaQ) |
|||
{ |
|||
writer.WriteLiteral((uint)quantParams.QMatrix[(int)Av1Plane.V], 4); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static void WriteSegmentationParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, int planesCount) |
|||
{ |
|||
Guard.IsFalse(frameInfo.SegmentationParameters.SegmentationEnabled, nameof(frameInfo.SegmentationParameters.SegmentationEnabled), "Segmentatino not supported yet."); |
|||
writer.WriteBoolean(false); |
|||
} |
|||
|
|||
private static void WriteLoopFilterParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, int planesCount) |
|||
{ |
|||
_ = writer; |
|||
_ = sequenceHeader; |
|||
_ = frameInfo; |
|||
_ = planesCount; |
|||
|
|||
// TODO: Parse more stuff.
|
|||
} |
|||
|
|||
private static void WriteTransformMode(ref Av1BitStreamWriter writer, ObuFrameHeader frameInfo) |
|||
{ |
|||
if (!frameInfo.CodedLossless) |
|||
{ |
|||
writer.WriteBoolean(frameInfo.TransformMode == Av1TransformMode.Select); |
|||
} |
|||
} |
|||
|
|||
private static void WriteLoopRestorationParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, int planesCount) |
|||
{ |
|||
_ = writer; |
|||
_ = sequenceHeader; |
|||
_ = frameInfo; |
|||
_ = planesCount; |
|||
|
|||
// TODO: Parse more stuff.
|
|||
} |
|||
|
|||
private static void WriteCdefParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, int planesCount) |
|||
{ |
|||
_ = writer; |
|||
_ = sequenceHeader; |
|||
_ = frameInfo; |
|||
_ = planesCount; |
|||
|
|||
// TODO: Parse more stuff.
|
|||
} |
|||
|
|||
private static void WriteGlobalMotionParameters(ref Av1BitStreamWriter writer, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, bool isIntraFrame) |
|||
{ |
|||
_ = writer; |
|||
_ = sequenceHeader; |
|||
_ = frameInfo; |
|||
|
|||
// Nothing to be written for INTRA frames.
|
|||
Guard.IsTrue(isIntraFrame, nameof(isIntraFrame), "Still picture contains only INTRA frames."); |
|||
} |
|||
|
|||
private static void WriteFrameReferenceMode(ref Av1BitStreamWriter writer, bool isIntraFrame) |
|||
{ |
|||
_ = writer; |
|||
|
|||
// Nothing to be written for INTRA frames.
|
|||
Guard.IsTrue(isIntraFrame, nameof(isIntraFrame), "Still picture contains only INTRA frames."); |
|||
} |
|||
|
|||
private static void WriteSkipModeParameters(ref Av1BitStreamWriter writer, bool isIntraFrame) |
|||
{ |
|||
_ = writer; |
|||
|
|||
// Nothing to be written for INTRA frames.
|
|||
Guard.IsTrue(isIntraFrame, nameof(isIntraFrame), "Still picture contains only INTRA frames."); |
|||
} |
|||
|
|||
private static void WriteFilmGrainFilterParameters(ref Av1BitStreamWriter writer, ObuFilmGrainParameters filmGrainInfo) |
|||
{ |
|||
_ = writer; |
|||
_ = filmGrainInfo; |
|||
|
|||
// Film grain filter not supported yet
|
|||
} |
|||
} |
|||
Loading…
Reference in new issue