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