xref: /aosp_15_r20/external/libgav1/src/film_grain.h (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1*09537850SAkhilesh Sanikop /*
2*09537850SAkhilesh Sanikop  * Copyright 2020 The libgav1 Authors
3*09537850SAkhilesh Sanikop  *
4*09537850SAkhilesh Sanikop  * Licensed under the Apache License, Version 2.0 (the "License");
5*09537850SAkhilesh Sanikop  * you may not use this file except in compliance with the License.
6*09537850SAkhilesh Sanikop  * You may obtain a copy of the License at
7*09537850SAkhilesh Sanikop  *
8*09537850SAkhilesh Sanikop  *      http://www.apache.org/licenses/LICENSE-2.0
9*09537850SAkhilesh Sanikop  *
10*09537850SAkhilesh Sanikop  * Unless required by applicable law or agreed to in writing, software
11*09537850SAkhilesh Sanikop  * distributed under the License is distributed on an "AS IS" BASIS,
12*09537850SAkhilesh Sanikop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*09537850SAkhilesh Sanikop  * See the License for the specific language governing permissions and
14*09537850SAkhilesh Sanikop  * limitations under the License.
15*09537850SAkhilesh Sanikop  */
16*09537850SAkhilesh Sanikop 
17*09537850SAkhilesh Sanikop #ifndef LIBGAV1_SRC_FILM_GRAIN_H_
18*09537850SAkhilesh Sanikop #define LIBGAV1_SRC_FILM_GRAIN_H_
19*09537850SAkhilesh Sanikop 
20*09537850SAkhilesh Sanikop #include <atomic>
21*09537850SAkhilesh Sanikop #include <cstddef>
22*09537850SAkhilesh Sanikop #include <cstdint>
23*09537850SAkhilesh Sanikop #include <memory>
24*09537850SAkhilesh Sanikop #include <type_traits>
25*09537850SAkhilesh Sanikop 
26*09537850SAkhilesh Sanikop #include "src/dsp/common.h"
27*09537850SAkhilesh Sanikop #include "src/dsp/dsp.h"
28*09537850SAkhilesh Sanikop #include "src/dsp/film_grain_common.h"
29*09537850SAkhilesh Sanikop #include "src/utils/array_2d.h"
30*09537850SAkhilesh Sanikop #include "src/utils/constants.h"
31*09537850SAkhilesh Sanikop #include "src/utils/cpu.h"
32*09537850SAkhilesh Sanikop #include "src/utils/threadpool.h"
33*09537850SAkhilesh Sanikop #include "src/utils/types.h"
34*09537850SAkhilesh Sanikop #include "src/utils/vector.h"
35*09537850SAkhilesh Sanikop 
36*09537850SAkhilesh Sanikop namespace libgav1 {
37*09537850SAkhilesh Sanikop 
38*09537850SAkhilesh Sanikop // Film grain synthesis function signature. Section 7.18.3.
39*09537850SAkhilesh Sanikop // This function generates film grain noise and blends the noise with the
40*09537850SAkhilesh Sanikop // decoded frame.
41*09537850SAkhilesh Sanikop // |source_plane_y|, |source_plane_u|, and |source_plane_v| are the plane
42*09537850SAkhilesh Sanikop // buffers of the decoded frame. They are blended with the film grain noise and
43*09537850SAkhilesh Sanikop // written to |dest_plane_y|, |dest_plane_u|, and |dest_plane_v| as final
44*09537850SAkhilesh Sanikop // output for display. |source_plane_p| and |dest_plane_p| (where p is y, u, or
45*09537850SAkhilesh Sanikop // v) may point to the same buffer, in which case the film grain noise is added
46*09537850SAkhilesh Sanikop // in place.
47*09537850SAkhilesh Sanikop // |film_grain_params| are parameters read from frame header.
48*09537850SAkhilesh Sanikop // |is_monochrome| is true indicates only Y plane needs to be processed.
49*09537850SAkhilesh Sanikop // |color_matrix_is_identity| is true if the matrix_coefficients field in the
50*09537850SAkhilesh Sanikop // sequence header's color config is is MC_IDENTITY.
51*09537850SAkhilesh Sanikop // |width| is the upscaled width of the frame.
52*09537850SAkhilesh Sanikop // |height| is the frame height.
53*09537850SAkhilesh Sanikop // |subsampling_x| and |subsampling_y| are subsamplings for UV planes, not used
54*09537850SAkhilesh Sanikop // if |is_monochrome| is true.
55*09537850SAkhilesh Sanikop // Returns true on success, or false on failure (e.g., out of memory).
56*09537850SAkhilesh Sanikop using FilmGrainSynthesisFunc = bool (*)(
57*09537850SAkhilesh Sanikop     const void* source_plane_y, ptrdiff_t source_stride_y,
58*09537850SAkhilesh Sanikop     const void* source_plane_u, ptrdiff_t source_stride_u,
59*09537850SAkhilesh Sanikop     const void* source_plane_v, ptrdiff_t source_stride_v,
60*09537850SAkhilesh Sanikop     const FilmGrainParams& film_grain_params, bool is_monochrome,
61*09537850SAkhilesh Sanikop     bool color_matrix_is_identity, int width, int height, int subsampling_x,
62*09537850SAkhilesh Sanikop     int subsampling_y, void* dest_plane_y, ptrdiff_t dest_stride_y,
63*09537850SAkhilesh Sanikop     void* dest_plane_u, ptrdiff_t dest_stride_u, void* dest_plane_v,
64*09537850SAkhilesh Sanikop     ptrdiff_t dest_stride_v);
65*09537850SAkhilesh Sanikop 
66*09537850SAkhilesh Sanikop // Section 7.18.3.5. Add noise synthesis process.
67*09537850SAkhilesh Sanikop template <int bitdepth>
68*09537850SAkhilesh Sanikop class FilmGrain {
69*09537850SAkhilesh Sanikop  public:
70*09537850SAkhilesh Sanikop   using GrainType =
71*09537850SAkhilesh Sanikop       typename std::conditional<bitdepth == 8, int8_t, int16_t>::type;
72*09537850SAkhilesh Sanikop 
73*09537850SAkhilesh Sanikop   FilmGrain(const FilmGrainParams& params, bool is_monochrome,
74*09537850SAkhilesh Sanikop             bool color_matrix_is_identity, int subsampling_x, int subsampling_y,
75*09537850SAkhilesh Sanikop             int width, int height, ThreadPool* thread_pool);
76*09537850SAkhilesh Sanikop 
77*09537850SAkhilesh Sanikop   // Note: These static methods are declared public so that the unit tests can
78*09537850SAkhilesh Sanikop   // call them.
79*09537850SAkhilesh Sanikop 
80*09537850SAkhilesh Sanikop   static void GenerateLumaGrain(const FilmGrainParams& params,
81*09537850SAkhilesh Sanikop                                 GrainType* luma_grain);
82*09537850SAkhilesh Sanikop 
83*09537850SAkhilesh Sanikop   // Generates white noise arrays u_grain and v_grain chroma_width samples wide
84*09537850SAkhilesh Sanikop   // and chroma_height samples high.
85*09537850SAkhilesh Sanikop   static void GenerateChromaGrains(const FilmGrainParams& params,
86*09537850SAkhilesh Sanikop                                    int chroma_width, int chroma_height,
87*09537850SAkhilesh Sanikop                                    GrainType* u_grain, GrainType* v_grain);
88*09537850SAkhilesh Sanikop 
89*09537850SAkhilesh Sanikop   // Copies rows from |noise_stripes| to |noise_image|, skipping rows that are
90*09537850SAkhilesh Sanikop   // subject to overlap.
91*09537850SAkhilesh Sanikop   static void ConstructNoiseImage(const Array2DView<GrainType>* noise_stripes,
92*09537850SAkhilesh Sanikop                                   int width, int height, int subsampling_x,
93*09537850SAkhilesh Sanikop                                   int subsampling_y, int stripe_start_offset,
94*09537850SAkhilesh Sanikop                                   Array2D<GrainType>* noise_image);
95*09537850SAkhilesh Sanikop 
96*09537850SAkhilesh Sanikop   // Combines the film grain with the image data.
97*09537850SAkhilesh Sanikop   bool AddNoise(const uint8_t* source_plane_y, ptrdiff_t source_stride_y,
98*09537850SAkhilesh Sanikop                 const uint8_t* source_plane_u, const uint8_t* source_plane_v,
99*09537850SAkhilesh Sanikop                 ptrdiff_t source_stride_uv, uint8_t* dest_plane_y,
100*09537850SAkhilesh Sanikop                 ptrdiff_t dest_stride_y, uint8_t* dest_plane_u,
101*09537850SAkhilesh Sanikop                 uint8_t* dest_plane_v, ptrdiff_t dest_stride_uv);
102*09537850SAkhilesh Sanikop 
103*09537850SAkhilesh Sanikop  private:
104*09537850SAkhilesh Sanikop   using Pixel =
105*09537850SAkhilesh Sanikop       typename std::conditional<bitdepth == 8, uint8_t, uint16_t>::type;
106*09537850SAkhilesh Sanikop   static constexpr int kScalingLutLength =
107*09537850SAkhilesh Sanikop       (bitdepth == 10)
108*09537850SAkhilesh Sanikop           ? (kScalingLookupTableSize + kScalingLookupTablePadding) << 2
109*09537850SAkhilesh Sanikop           : kScalingLookupTableSize + kScalingLookupTablePadding;
110*09537850SAkhilesh Sanikop 
111*09537850SAkhilesh Sanikop   bool Init();
112*09537850SAkhilesh Sanikop 
113*09537850SAkhilesh Sanikop   // Allocates noise_stripes_.
114*09537850SAkhilesh Sanikop   bool AllocateNoiseStripes();
115*09537850SAkhilesh Sanikop 
116*09537850SAkhilesh Sanikop   bool AllocateNoiseImage();
117*09537850SAkhilesh Sanikop 
118*09537850SAkhilesh Sanikop   void BlendNoiseChromaWorker(const dsp::Dsp& dsp, const Plane* planes,
119*09537850SAkhilesh Sanikop                               int num_planes, std::atomic<int>* job_counter,
120*09537850SAkhilesh Sanikop                               int min_value, int max_chroma,
121*09537850SAkhilesh Sanikop                               const uint8_t* source_plane_y,
122*09537850SAkhilesh Sanikop                               ptrdiff_t source_stride_y,
123*09537850SAkhilesh Sanikop                               const uint8_t* source_plane_u,
124*09537850SAkhilesh Sanikop                               const uint8_t* source_plane_v,
125*09537850SAkhilesh Sanikop                               ptrdiff_t source_stride_uv, uint8_t* dest_plane_u,
126*09537850SAkhilesh Sanikop                               uint8_t* dest_plane_v, ptrdiff_t dest_stride_uv);
127*09537850SAkhilesh Sanikop 
128*09537850SAkhilesh Sanikop   void BlendNoiseLumaWorker(const dsp::Dsp& dsp, std::atomic<int>* job_counter,
129*09537850SAkhilesh Sanikop                             int min_value, int max_luma,
130*09537850SAkhilesh Sanikop                             const uint8_t* source_plane_y,
131*09537850SAkhilesh Sanikop                             ptrdiff_t source_stride_y, uint8_t* dest_plane_y,
132*09537850SAkhilesh Sanikop                             ptrdiff_t dest_stride_y);
133*09537850SAkhilesh Sanikop 
134*09537850SAkhilesh Sanikop   const FilmGrainParams& params_;
135*09537850SAkhilesh Sanikop   const bool is_monochrome_;
136*09537850SAkhilesh Sanikop   const bool color_matrix_is_identity_;
137*09537850SAkhilesh Sanikop   const int subsampling_x_;
138*09537850SAkhilesh Sanikop   const int subsampling_y_;
139*09537850SAkhilesh Sanikop   // Frame width and height.
140*09537850SAkhilesh Sanikop   const int width_;
141*09537850SAkhilesh Sanikop   const int height_;
142*09537850SAkhilesh Sanikop   // Section 7.18.3.3, Dimensions of the noise templates for chroma, which are
143*09537850SAkhilesh Sanikop   // known as CbGrain and CrGrain.
144*09537850SAkhilesh Sanikop   // These templates are used to construct the noise image for each plane by
145*09537850SAkhilesh Sanikop   // copying 32x32 blocks with pseudorandom offsets, into "noise stripes."
146*09537850SAkhilesh Sanikop   // The noise template known as LumaGrain array is an 82x73 block.
147*09537850SAkhilesh Sanikop   // The height and width of the templates for chroma become 44 and 38 under
148*09537850SAkhilesh Sanikop   // subsampling, respectively.
149*09537850SAkhilesh Sanikop   //  For more details see:
150*09537850SAkhilesh Sanikop   // A. Norkin and N. Birkbeck, "Film Grain Synthesis for AV1 Video Codec," 2018
151*09537850SAkhilesh Sanikop   // Data Compression Conference, Snowbird, UT, 2018, pp. 3-12.
152*09537850SAkhilesh Sanikop   const int template_uv_width_;
153*09537850SAkhilesh Sanikop   const int template_uv_height_;
154*09537850SAkhilesh Sanikop   // LumaGrain. The luma_grain array contains white noise generated for luma.
155*09537850SAkhilesh Sanikop   // The array size is fixed but subject to further optimization for SIMD.
156*09537850SAkhilesh Sanikop   GrainType luma_grain_[kLumaHeight * kLumaWidth];
157*09537850SAkhilesh Sanikop   // CbGrain and CrGrain. The maximum size of the u_grain and v_grain arrays is
158*09537850SAkhilesh Sanikop   // kMaxChromaHeight * kMaxChromaWidth. The actual size is
159*09537850SAkhilesh Sanikop   // template_uv_height_ * template_uv_width_.
160*09537850SAkhilesh Sanikop   GrainType u_grain_[kMaxChromaHeight * kMaxChromaWidth];
161*09537850SAkhilesh Sanikop   GrainType v_grain_[kMaxChromaHeight * kMaxChromaWidth];
162*09537850SAkhilesh Sanikop   // Scaling lookup tables.
163*09537850SAkhilesh Sanikop   int16_t scaling_lut_y_[kScalingLutLength];
164*09537850SAkhilesh Sanikop   int16_t* scaling_lut_u_ = nullptr;
165*09537850SAkhilesh Sanikop   int16_t* scaling_lut_v_ = nullptr;
166*09537850SAkhilesh Sanikop   // If allocated, this buffer is 256 * 2 values long and scaling_lut_u_ and
167*09537850SAkhilesh Sanikop   // scaling_lut_v_ point into this buffer. Otherwise, scaling_lut_u_ and
168*09537850SAkhilesh Sanikop   // scaling_lut_v_ point to scaling_lut_y_.
169*09537850SAkhilesh Sanikop   std::unique_ptr<int16_t[]> scaling_lut_chroma_buffer_;
170*09537850SAkhilesh Sanikop 
171*09537850SAkhilesh Sanikop   // A two-dimensional array of noise data for each plane. Generated for each 32
172*09537850SAkhilesh Sanikop   // luma sample high stripe of the image. The first dimension is called
173*09537850SAkhilesh Sanikop   // luma_num. The second dimension is the size of one noise stripe.
174*09537850SAkhilesh Sanikop   //
175*09537850SAkhilesh Sanikop   // Each row of the Array2DView noise_stripes_[plane] is a conceptually
176*09537850SAkhilesh Sanikop   // two-dimensional array of |GrainType|s. The two-dimensional array of
177*09537850SAkhilesh Sanikop   // |GrainType|s is flattened into a one-dimensional buffer in this
178*09537850SAkhilesh Sanikop   // implementation.
179*09537850SAkhilesh Sanikop   //
180*09537850SAkhilesh Sanikop   // noise_stripes_[kPlaneY][luma_num] is an array that has 34 rows and
181*09537850SAkhilesh Sanikop   // |width_| columns and contains noise for the luma component.
182*09537850SAkhilesh Sanikop   //
183*09537850SAkhilesh Sanikop   // noise_stripes_[kPlaneU][luma_num] or noise_stripes_[kPlaneV][luma_num]
184*09537850SAkhilesh Sanikop   // is an array that has (34 >> subsampling_y_) rows and
185*09537850SAkhilesh Sanikop   // SubsampledValue(width_, subsampling_x_) columns and contains noise for the
186*09537850SAkhilesh Sanikop   // chroma components.
187*09537850SAkhilesh Sanikop   Array2DView<GrainType> noise_stripes_[kMaxPlanes];
188*09537850SAkhilesh Sanikop   // Owns the memory that the elements of noise_stripes_ point to.
189*09537850SAkhilesh Sanikop   std::unique_ptr<GrainType[]> noise_buffer_;
190*09537850SAkhilesh Sanikop 
191*09537850SAkhilesh Sanikop   Array2D<GrainType> noise_image_[kMaxPlanes];
192*09537850SAkhilesh Sanikop   ThreadPool* const thread_pool_;
193*09537850SAkhilesh Sanikop };
194*09537850SAkhilesh Sanikop 
195*09537850SAkhilesh Sanikop }  // namespace libgav1
196*09537850SAkhilesh Sanikop 
197*09537850SAkhilesh Sanikop #endif  // LIBGAV1_SRC_FILM_GRAIN_H_
198