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