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