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