diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFilmGrainParameters.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFilmGrainParameters.cs
index 67b8f352ed..f4c0888dce 100644
--- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFilmGrainParameters.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFilmGrainParameters.cs
@@ -1,9 +1,176 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Diagnostics.Metrics;
+using System.Runtime.Intrinsics.X86;
+using System;
+
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuFilmGrainParameters
{
+ ///
+ /// Gets or sets ApplyGrain. A value equal to 1 specifies that film grain should be added to this frame. A value equal to 0 specifies that film
+ /// grain should not be added.
+ ///
public bool ApplyGrain { get; set; }
+
+ ///
+ /// Gets or sets GrainSeed. This value specifies the starting value for the pseudo-random numbers used during film grain synthesis.
+ ///
+ public uint GrainSeed { get; set; }
+
+ ///
+ /// Gets or sets UpdateGrain. A value equal to 1 means that a new set of parameters should be sent. A value equal to 0 means that the
+ /// previous set of parameters should be used.
+ ///
+ public bool UpdateGrain { get; set; }
+
+ ///
+ /// Gets or sets FilmGrainParamsRefIdx. Indicates which reference frame contains the film grain parameters to be used for this frame.
+ /// It is a requirement of bitstream conformance that FilmGrainParamsRefIdx is equal to ref_frame_idx[ j ] for some value
+ /// of j in the range 0 to REFS_PER_FRAME - 1.
+ ///
+ public uint FilmGrainParamsRefidx { get; set; }
+
+ ///
+ /// Gets or sets NumYPoints. Specifies the number of points for the piece-wise linear scaling function of the luma component.
+ /// It is a requirement of bitstream conformance that NumYPoints is less than or equal to 14.
+ ///
+ public uint NumYPoints { get; set; }
+
+ ///
+ /// Gets or sets PointYValue. Represents the x (luma value) coordinate for the i-th point of the piecewise linear scaling function for
+ /// luma component.The values are signaled on the scale of 0..255. (In case of 10 bit video, these values correspond to
+ /// luma values divided by 4. In case of 12 bit video, these values correspond to luma values divided by 16.)
+ ///
+ /// If i is greater than 0, it is a requirement of bitstream conformance that point_y_value[ i ] is greater than point_y_value[ i - 1] (this ensures the x coordinates are specified in increasing order).
+ ///
+ public uint[]? PointYValue { get; set; }
+
+ ///
+ /// Gets or sets PointYScaling. Represents the scaling (output) value for the i-th point of the piecewise linear scaling function for luma component.
+ ///
+ public uint[]? PointYScaling { get; set; }
+
+ ///
+ /// Gets or sets ChromaScalingFromLuma. Specifies that the chroma scaling is inferred from the luma scaling.
+ ///
+ public bool ChromaScalingFromLuma { get; set; }
+
+ ///
+ /// Gets or sets NumCbPoints. Specifies the number of points for the piece-wise linear scaling function of the cb component.
+ /// It is a requirement of bitstream conformance that NumCbPoints is less than or equal to 10.
+ ///
+ public uint NumCbPoints { get; set; }
+
+ ///
+ /// Gets or sets NumCrPoints. Specifies represents the number of points for the piece-wise linear scaling function of the cr component.
+ /// It is a requirement of bitstream conformance that NumCrPoints is less than or equal to 10.
+ ///
+ public uint NumCrPoints { get; set; }
+
+ ///
+ /// Gets or sets PointCbValue. Represents the x coordinate for the i-th point of the piece-wise linear scaling function for cb
+ /// component.The values are signaled on the scale of 0..255.
+ /// If i is greater than 0, it is a requirement of bitstream conformance that point_cb_value[ i ] is greater than point_cb_value[ i - 1 ].
+ ///
+ public uint[]? PointCbValue { get; set; }
+
+ ///
+ /// Gets or sets PointCbScaling. Represents the scaling (output) value for the i-th point of the piecewise linear scaling function for cb component.
+ ///
+ public uint[]? PointCbScaling { get; set; }
+
+ ///
+ /// Gets or sets PointCrValue. Represents the x coordinate for the i-th point of the piece-wise linear scaling function for cr component.
+ /// The values are signaled on the scale of 0..255.
+ /// If i is greater than 0, it is a requirement of bitstream conformance that point_cr_value[ i ] is greater than point_cr_value[ i - 1 ].
+ ///
+ public uint[]? PointCrValue { get; set; }
+
+ ///
+ /// Gets or sets PointCrScaling. Represents the scaling (output) value for the i-th point of the piecewise linear scaling function for cr component.
+ ///
+ public uint[]? PointCrScaling { get; set; }
+
+ ///
+ /// Gets or sets GrainScalingMinus8. represents the shift – 8 applied to the values of the chroma component. The
+ /// grain_scaling_minus_8 can take values of 0..3 and determines the range and quantization step of the standard deviation of film grain.
+ ///
+ public uint GrainScalingMinus8 { get; set; }
+
+ ///
+ /// Gets or sets ArCoeffLag. Specifies the number of auto-regressive coefficients for luma and chroma.
+ ///
+ public uint ArCoeffLag { get; set; }
+
+ ///
+ /// Gets or sets ArCoeffsYPlus128. Specifies auto-regressive coefficients used for the Y plane.
+ ///
+ public uint[]? ArCoeffsYPlus128 { get; set; }
+
+ ///
+ /// Gets or sets ArCoeffsCbPlus128. Specifies auto-regressive coefficients used for the U plane.
+ ///
+ public uint[]? ArCoeffsCbPlus128 { get; set; }
+
+ ///
+ /// Gets or sets ArCoeffsCrPlus128. Specifies auto-regressive coefficients used for the V plane.
+ ///
+ public uint[]? ArCoeffsCrPlus128 { get; set; }
+
+ ///
+ /// Gets or sets ArCoeffShiftMinus6. Specifies the range of the auto-regressive coefficients. Values of 0, 1, 2, and 3 correspond to the
+ /// ranges for auto-regressive coefficients of[-2, 2), [-1, 1), [-0.5, 0.5) and [-0.25, 0.25) respectively.
+ ///
+ public uint ArCoeffShiftMinus6 { get; set; }
+
+ ///
+ /// Gets or sets GrainScaleShift. Specifies how much the Gaussian random numbers should be scaled down during the grain synthesis process.
+ ///
+ public uint GrainScaleShift { get; set; }
+
+ ///
+ /// Gets or sets CbMult. Represents a multiplier for the cb component used in derivation of the input index to the cb component scaling function.
+ ///
+ public uint CbMult { get; set; }
+
+ ///
+ /// Gets or sets CbLumaMult. Represents a multiplier for the average luma component used in derivation of the input index to the cb component scaling function.
+ ///
+ public uint CbLumaMult { get; set; }
+
+ ///
+ /// Gets or sets CbOffset. Represents an offset used in derivation of the input index to the cb component scaling function.
+ ///
+ public uint CbOffset { get; set; }
+
+ ///
+ /// Gets or sets CrMult. Represents a multiplier for the cr component used in derivation of the input index to the cr component scaling function.
+ ///
+ public uint CrMult { get; set; }
+
+ ///
+ /// Gets or sets CrLumaMult. Represents a multiplier for the average luma component used in derivation of the input index to the cr component scaling function.
+ ///
+ public uint CrLumaMult { get; set; }
+
+ ///
+ /// Gets or sets CrOffset. Represents an offset used in derivation of the input index to the cr component scaling function.
+ ///
+ public uint CrOffset { get; set; }
+
+ ///
+ /// Gets or sets OverlapFlag. Equal to true indicates that the overlap between film grain blocks shall be applied. overlap_flag equal to false
+ /// indicates that the overlap between film grain blocks shall not be applied.
+ ///
+ public bool OverlapFlag { get; set; }
+
+ ///
+ /// Gets or sets ClipToRestrictedRange. equal to true indicates that clipping to the restricted (studio) range shall be applied to the sample
+ /// values after adding the film grain(see the semantics for color_range for an explanation of studio swing).
+ /// clip_to_restricted_range equal to false indicates that clipping to the full range shall be applied to the sample values after adding the film grain.
+ ///
+ public bool ClipToRestrictedRange { get; set; }
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
index fc41dd5b24..83feaddb69 100644
--- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
@@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
@@ -1523,8 +1521,131 @@ internal class ObuReader
return grainParams;
}
- // TODO: Implement parsing.
- throw new NotImplementedException();
+ grainParams.GrainSeed = reader.ReadLiteral(16);
+
+ if (frameInfo.FrameType == ObuFrameType.InterFrame)
+ {
+ grainParams.UpdateGrain = reader.ReadBoolean();
+ }
+ else
+ {
+ grainParams.UpdateGrain = false;
+ }
+
+ if (!grainParams.UpdateGrain)
+ {
+ grainParams.FilmGrainParamsRefidx = reader.ReadLiteral(3);
+ uint tempGrainSeed = grainParams.GrainSeed;
+
+ // TODO: implement load_grain_params
+ // load_grain_params(film_grain_params_ref_idx)
+ grainParams.GrainSeed = tempGrainSeed;
+ return grainParams;
+ }
+
+ grainParams.NumYPoints = reader.ReadLiteral(4);
+ grainParams.PointYValue = new uint[grainParams.NumYPoints];
+ grainParams.PointYScaling = new uint[grainParams.NumYPoints];
+ for (int i = 0; i < grainParams.NumYPoints; i++)
+ {
+ grainParams.PointYValue[i] = reader.ReadLiteral(8);
+ grainParams.PointYScaling[i] = reader.ReadLiteral(8);
+ }
+
+ if (sequenceHeader.ColorConfig.IsMonochrome)
+ {
+ grainParams.ChromaScalingFromLuma = false;
+ }
+ else
+ {
+ grainParams.ChromaScalingFromLuma = reader.ReadBoolean();
+ }
+
+ if (sequenceHeader.ColorConfig.IsMonochrome ||
+ grainParams.ChromaScalingFromLuma ||
+ (sequenceHeader.ColorConfig.SubSamplingX && sequenceHeader.ColorConfig.SubSamplingY && grainParams.NumYPoints == 0))
+ {
+ grainParams.NumCbPoints = 0;
+ grainParams.NumCrPoints = 0;
+ }
+ else
+ {
+ grainParams.NumCbPoints = reader.ReadLiteral(4);
+ grainParams.PointCbValue = new uint[grainParams.NumCbPoints];
+ grainParams.PointCbScaling = new uint[grainParams.NumCbPoints];
+ for (int i = 0; i < grainParams.NumCbPoints; i++)
+ {
+ grainParams.PointCbValue[i] = reader.ReadLiteral(8);
+ grainParams.PointCbScaling[i] = reader.ReadLiteral(8);
+ }
+
+ grainParams.NumCrPoints = reader.ReadLiteral(4);
+ grainParams.PointCrValue = new uint[grainParams.NumCrPoints];
+ grainParams.PointCrScaling = new uint[grainParams.NumCrPoints];
+ for (int i = 0; i < grainParams.NumCbPoints; i++)
+ {
+ grainParams.PointCrValue[i] = reader.ReadLiteral(8);
+ grainParams.PointCrScaling[i] = reader.ReadLiteral(8);
+ }
+ }
+
+ grainParams.GrainScalingMinus8 = reader.ReadLiteral(2);
+ grainParams.ArCoeffLag = reader.ReadLiteral(2);
+ uint numPosLuma = 2 * grainParams.ArCoeffLag * (grainParams.ArCoeffLag + 1);
+
+ uint numPosChroma = 0;
+ if (grainParams.NumYPoints != 0)
+ {
+ numPosChroma = numPosLuma + 1;
+ grainParams.ArCoeffsYPlus128 = new uint[numPosLuma];
+ for (int i = 0; i < numPosLuma; i++)
+ {
+ grainParams.ArCoeffsYPlus128[i] = reader.ReadLiteral(8);
+ }
+ }
+ else
+ {
+ numPosChroma = numPosLuma;
+ }
+
+ if (grainParams.ChromaScalingFromLuma || grainParams.NumCbPoints != 0)
+ {
+ grainParams.ArCoeffsCbPlus128 = new uint[numPosChroma];
+ for (int i = 0; i < numPosChroma; i++)
+ {
+ grainParams.ArCoeffsCbPlus128[i] = reader.ReadLiteral(8);
+ }
+ }
+
+ if (grainParams.ChromaScalingFromLuma || grainParams.NumCrPoints != 0)
+ {
+ grainParams.ArCoeffsCrPlus128 = new uint[numPosChroma];
+ for (int i = 0; i < numPosChroma; i++)
+ {
+ grainParams.ArCoeffsCrPlus128[i] = reader.ReadLiteral(8);
+ }
+ }
+
+ grainParams.ArCoeffShiftMinus6 = reader.ReadLiteral(2);
+ grainParams.GrainScaleShift = reader.ReadLiteral(2);
+ if (grainParams.NumCbPoints != 0)
+ {
+ grainParams.CbMult = reader.ReadLiteral(8);
+ grainParams.CbLumaMult = reader.ReadLiteral(8);
+ grainParams.CbOffset = reader.ReadLiteral(8);
+ }
+
+ if (grainParams.NumCrPoints != 0)
+ {
+ grainParams.CrMult = reader.ReadLiteral(8);
+ grainParams.CrLumaMult = reader.ReadLiteral(8);
+ grainParams.CrOffset = reader.ReadLiteral(8);
+ }
+
+ grainParams.OverlapFlag = reader.ReadBoolean();
+ grainParams.ClipToRestrictedRange = reader.ReadBoolean();
+
+ return grainParams;
}
private static bool IsValidSequenceLevel(int sequenceLevelIndex)