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 77 // Note: These static methods are declared public so that the unit tests can 78 // call them. 79 80 static void GenerateLumaGrain(const FilmGrainParams& params, 81 GrainType* luma_grain); 82 83 // Generates white noise arrays u_grain and v_grain chroma_width samples wide 84 // and chroma_height samples high. 85 static void GenerateChromaGrains(const FilmGrainParams& params, 86 int chroma_width, int chroma_height, 87 GrainType* u_grain, GrainType* v_grain); 88 89 // Copies rows from |noise_stripes| to |noise_image|, skipping rows that are 90 // subject to overlap. 91 static void ConstructNoiseImage(const Array2DView<GrainType>* noise_stripes, 92 int width, int height, int subsampling_x, 93 int subsampling_y, int stripe_start_offset, 94 Array2D<GrainType>* noise_image); 95 96 // Combines the film grain with the image data. 97 bool AddNoise(const uint8_t* source_plane_y, ptrdiff_t source_stride_y, 98 const uint8_t* source_plane_u, const uint8_t* source_plane_v, 99 ptrdiff_t source_stride_uv, uint8_t* dest_plane_y, 100 ptrdiff_t dest_stride_y, uint8_t* dest_plane_u, 101 uint8_t* dest_plane_v, ptrdiff_t dest_stride_uv); 102 103 private: 104 using Pixel = 105 typename std::conditional<bitdepth == 8, uint8_t, uint16_t>::type; 106 static constexpr int kScalingLutLength = 107 (bitdepth == 10) 108 ? (kScalingLookupTableSize + kScalingLookupTablePadding) << 2 109 : kScalingLookupTableSize + kScalingLookupTablePadding; 110 111 bool Init(); 112 113 // Allocates noise_stripes_. 114 bool AllocateNoiseStripes(); 115 116 bool AllocateNoiseImage(); 117 118 void BlendNoiseChromaWorker(const dsp::Dsp& dsp, const Plane* planes, 119 int num_planes, std::atomic<int>* job_counter, 120 int min_value, int max_chroma, 121 const uint8_t* source_plane_y, 122 ptrdiff_t source_stride_y, 123 const uint8_t* source_plane_u, 124 const uint8_t* source_plane_v, 125 ptrdiff_t source_stride_uv, uint8_t* dest_plane_u, 126 uint8_t* dest_plane_v, ptrdiff_t dest_stride_uv); 127 128 void BlendNoiseLumaWorker(const dsp::Dsp& dsp, std::atomic<int>* job_counter, 129 int min_value, int max_luma, 130 const uint8_t* source_plane_y, 131 ptrdiff_t source_stride_y, uint8_t* dest_plane_y, 132 ptrdiff_t dest_stride_y); 133 134 const FilmGrainParams& params_; 135 const bool is_monochrome_; 136 const bool color_matrix_is_identity_; 137 const int subsampling_x_; 138 const int subsampling_y_; 139 // Frame width and height. 140 const int width_; 141 const int height_; 142 // Section 7.18.3.3, Dimensions of the noise templates for chroma, which are 143 // known as CbGrain and CrGrain. 144 // These templates are used to construct the noise image for each plane by 145 // copying 32x32 blocks with pseudorandom offsets, into "noise stripes." 146 // The noise template known as LumaGrain array is an 82x73 block. 147 // The height and width of the templates for chroma become 44 and 38 under 148 // subsampling, respectively. 149 // For more details see: 150 // A. Norkin and N. Birkbeck, "Film Grain Synthesis for AV1 Video Codec," 2018 151 // Data Compression Conference, Snowbird, UT, 2018, pp. 3-12. 152 const int template_uv_width_; 153 const int template_uv_height_; 154 // LumaGrain. The luma_grain array contains white noise generated for luma. 155 // The array size is fixed but subject to further optimization for SIMD. 156 GrainType luma_grain_[kLumaHeight * kLumaWidth]; 157 // CbGrain and CrGrain. The maximum size of the u_grain and v_grain arrays is 158 // kMaxChromaHeight * kMaxChromaWidth. The actual size is 159 // template_uv_height_ * template_uv_width_. 160 GrainType u_grain_[kMaxChromaHeight * kMaxChromaWidth]; 161 GrainType v_grain_[kMaxChromaHeight * kMaxChromaWidth]; 162 // Scaling lookup tables. 163 int16_t scaling_lut_y_[kScalingLutLength]; 164 int16_t* scaling_lut_u_ = nullptr; 165 int16_t* scaling_lut_v_ = nullptr; 166 // If allocated, this buffer is 256 * 2 values long and scaling_lut_u_ and 167 // scaling_lut_v_ point into this buffer. Otherwise, scaling_lut_u_ and 168 // scaling_lut_v_ point to scaling_lut_y_. 169 std::unique_ptr<int16_t[]> scaling_lut_chroma_buffer_; 170 171 // A two-dimensional array of noise data for each plane. Generated for each 32 172 // luma sample high stripe of the image. The first dimension is called 173 // luma_num. The second dimension is the size of one noise stripe. 174 // 175 // Each row of the Array2DView noise_stripes_[plane] is a conceptually 176 // two-dimensional array of |GrainType|s. The two-dimensional array of 177 // |GrainType|s is flattened into a one-dimensional buffer in this 178 // implementation. 179 // 180 // noise_stripes_[kPlaneY][luma_num] is an array that has 34 rows and 181 // |width_| columns and contains noise for the luma component. 182 // 183 // noise_stripes_[kPlaneU][luma_num] or noise_stripes_[kPlaneV][luma_num] 184 // is an array that has (34 >> subsampling_y_) rows and 185 // SubsampledValue(width_, subsampling_x_) columns and contains noise for the 186 // chroma components. 187 Array2DView<GrainType> noise_stripes_[kMaxPlanes]; 188 // Owns the memory that the elements of noise_stripes_ point to. 189 std::unique_ptr<GrainType[]> noise_buffer_; 190 191 Array2D<GrainType> noise_image_[kMaxPlanes]; 192 ThreadPool* const thread_pool_; 193 }; 194 195 } // namespace libgav1 196 197 #endif // LIBGAV1_SRC_FILM_GRAIN_H_ 198