From 1d288d382b58a6a17fb65203819663dd1ceb9b9a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 26 Jun 2024 20:03:53 +0200 Subject: [PATCH] Implement ReadFilmGrainFilterParameters() --- .../ObuFilmGrainParameters.cs | 167 ++++++++++++++++++ .../Heif/Av1/OpenBitstreamUnit/ObuReader.cs | 129 +++++++++++++- 2 files changed, 292 insertions(+), 4 deletions(-) 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)