1*09537850SAkhilesh Sanikop /* 2*09537850SAkhilesh Sanikop * Copyright 2019 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_YUV_BUFFER_H_ 18*09537850SAkhilesh Sanikop #define LIBGAV1_SRC_YUV_BUFFER_H_ 19*09537850SAkhilesh Sanikop 20*09537850SAkhilesh Sanikop #include <cassert> 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/gav1/frame_buffer.h" 27*09537850SAkhilesh Sanikop #include "src/utils/compiler_attributes.h" 28*09537850SAkhilesh Sanikop #include "src/utils/constants.h" 29*09537850SAkhilesh Sanikop 30*09537850SAkhilesh Sanikop namespace libgav1 { 31*09537850SAkhilesh Sanikop 32*09537850SAkhilesh Sanikop class YuvBuffer { 33*09537850SAkhilesh Sanikop public: 34*09537850SAkhilesh Sanikop // Allocates the buffer. Returns true on success. Returns false on failure. 35*09537850SAkhilesh Sanikop // 36*09537850SAkhilesh Sanikop // * |width| and |height| are the image dimensions in pixels. 37*09537850SAkhilesh Sanikop // * |subsampling_x| and |subsampling_y| (either 0 or 1) specify the 38*09537850SAkhilesh Sanikop // subsampling of the width and height of the chroma planes, respectively. 39*09537850SAkhilesh Sanikop // * |left_border|, |right_border|, |top_border|, and |bottom_border| are 40*09537850SAkhilesh Sanikop // the sizes (in pixels) of the borders on the left, right, top, and 41*09537850SAkhilesh Sanikop // bottom sides, respectively. The four border sizes must all be a 42*09537850SAkhilesh Sanikop // multiple of 2. 43*09537850SAkhilesh Sanikop // * If |get_frame_buffer| is not null, it is invoked to allocate the memory. 44*09537850SAkhilesh Sanikop // If |get_frame_buffer| is null, YuvBuffer allocates the memory directly 45*09537850SAkhilesh Sanikop // and ignores the |callback_private_data| and |buffer_private_data| 46*09537850SAkhilesh Sanikop // parameters, which should be null. 47*09537850SAkhilesh Sanikop // 48*09537850SAkhilesh Sanikop // NOTE: The strides are a multiple of 16. Since the first row in each plane 49*09537850SAkhilesh Sanikop // is 16-byte aligned, subsequent rows are also 16-byte aligned. 50*09537850SAkhilesh Sanikop // 51*09537850SAkhilesh Sanikop // Example: bitdepth=8 width=20 height=6 left/right/top/bottom_border=2. The 52*09537850SAkhilesh Sanikop // diagram below shows how Realloc() allocates the data buffer for the Y 53*09537850SAkhilesh Sanikop // plane. 54*09537850SAkhilesh Sanikop // 55*09537850SAkhilesh Sanikop // 16-byte aligned 56*09537850SAkhilesh Sanikop // | 57*09537850SAkhilesh Sanikop // v 58*09537850SAkhilesh Sanikop // ++++++++++++++++++++++++pppppppp 59*09537850SAkhilesh Sanikop // ++++++++++++++++++++++++pppppppp 60*09537850SAkhilesh Sanikop // ++01234567890123456789++pppppppp 61*09537850SAkhilesh Sanikop // ++11234567890123456789++pppppppp 62*09537850SAkhilesh Sanikop // ++21234567890123456789++pppppppp 63*09537850SAkhilesh Sanikop // ++31234567890123456789++pppppppp 64*09537850SAkhilesh Sanikop // ++41234567890123456789++pppppppp 65*09537850SAkhilesh Sanikop // ++51234567890123456789++pppppppp 66*09537850SAkhilesh Sanikop // ++++++++++++++++++++++++pppppppp 67*09537850SAkhilesh Sanikop // ++++++++++++++++++++++++pppppppp 68*09537850SAkhilesh Sanikop // | | 69*09537850SAkhilesh Sanikop // |<-- stride (multiple of 16) ->| 70*09537850SAkhilesh Sanikop // 71*09537850SAkhilesh Sanikop // The video frame has 6 rows of 20 pixels each. Each row is shown as the 72*09537850SAkhilesh Sanikop // pattern r1234567890123456789, where |r| is 0, 1, 2, 3, 4, 5. 73*09537850SAkhilesh Sanikop // 74*09537850SAkhilesh Sanikop // Realloc() first adds a border of 2 pixels around the video frame. The 75*09537850SAkhilesh Sanikop // border pixels are shown as '+'. 76*09537850SAkhilesh Sanikop // 77*09537850SAkhilesh Sanikop // Each row is then padded to a multiple of the default alignment in bytes, 78*09537850SAkhilesh Sanikop // which is 16. The padding bytes are shown as lowercase 'p'. (Since 79*09537850SAkhilesh Sanikop // |bitdepth| is 8 in this example, each pixel is one byte.) The padded size 80*09537850SAkhilesh Sanikop // in bytes is the stride. In this example, the stride is 32 bytes. 81*09537850SAkhilesh Sanikop // 82*09537850SAkhilesh Sanikop // Finally, Realloc() aligns the first byte of frame data, which is the '0' 83*09537850SAkhilesh Sanikop // pixel/byte in the upper left corner of the frame, to the default (16-byte) 84*09537850SAkhilesh Sanikop // alignment boundary. 85*09537850SAkhilesh Sanikop // 86*09537850SAkhilesh Sanikop // TODO(wtc): Add a check for width and height limits to defend against 87*09537850SAkhilesh Sanikop // invalid bitstreams. 88*09537850SAkhilesh Sanikop bool Realloc(int bitdepth, bool is_monochrome, int width, int height, 89*09537850SAkhilesh Sanikop int8_t subsampling_x, int8_t subsampling_y, int left_border, 90*09537850SAkhilesh Sanikop int right_border, int top_border, int bottom_border, 91*09537850SAkhilesh Sanikop GetFrameBufferCallback get_frame_buffer, 92*09537850SAkhilesh Sanikop void* callback_private_data, void** buffer_private_data); 93*09537850SAkhilesh Sanikop bitdepth()94*09537850SAkhilesh Sanikop int bitdepth() const { return bitdepth_; } 95*09537850SAkhilesh Sanikop is_monochrome()96*09537850SAkhilesh Sanikop bool is_monochrome() const { return is_monochrome_; } 97*09537850SAkhilesh Sanikop subsampling_x()98*09537850SAkhilesh Sanikop int8_t subsampling_x() const { return subsampling_x_; } subsampling_y()99*09537850SAkhilesh Sanikop int8_t subsampling_y() const { return subsampling_y_; } 100*09537850SAkhilesh Sanikop width(int plane)101*09537850SAkhilesh Sanikop int width(int plane) const { 102*09537850SAkhilesh Sanikop return (plane == kPlaneY) ? y_width_ : uv_width_; 103*09537850SAkhilesh Sanikop } height(int plane)104*09537850SAkhilesh Sanikop int height(int plane) const { 105*09537850SAkhilesh Sanikop return (plane == kPlaneY) ? y_height_ : uv_height_; 106*09537850SAkhilesh Sanikop } 107*09537850SAkhilesh Sanikop 108*09537850SAkhilesh Sanikop // Returns border sizes in pixels. left_border(int plane)109*09537850SAkhilesh Sanikop int left_border(int plane) const { return left_border_[plane]; } right_border(int plane)110*09537850SAkhilesh Sanikop int right_border(int plane) const { return right_border_[plane]; } top_border(int plane)111*09537850SAkhilesh Sanikop int top_border(int plane) const { return top_border_[plane]; } bottom_border(int plane)112*09537850SAkhilesh Sanikop int bottom_border(int plane) const { return bottom_border_[plane]; } 113*09537850SAkhilesh Sanikop 114*09537850SAkhilesh Sanikop // Returns the alignment of frame buffer row in bytes. alignment()115*09537850SAkhilesh Sanikop int alignment() const { return kFrameBufferRowAlignment; } 116*09537850SAkhilesh Sanikop 117*09537850SAkhilesh Sanikop // Backup the current set of warnings and disable -Warray-bounds for the 118*09537850SAkhilesh Sanikop // following three functions as the compiler cannot, in all cases, determine 119*09537850SAkhilesh Sanikop // whether |plane| is within [0, kMaxPlanes), e.g., with a variable based for 120*09537850SAkhilesh Sanikop // loop. 121*09537850SAkhilesh Sanikop #ifdef __GNUC__ 122*09537850SAkhilesh Sanikop #pragma GCC diagnostic push 123*09537850SAkhilesh Sanikop #pragma GCC diagnostic ignored "-Warray-bounds" 124*09537850SAkhilesh Sanikop #endif 125*09537850SAkhilesh Sanikop // Returns the data buffer for |plane|. data(int plane)126*09537850SAkhilesh Sanikop uint8_t* data(int plane) { 127*09537850SAkhilesh Sanikop assert(plane >= 0); 128*09537850SAkhilesh Sanikop assert(static_cast<size_t>(plane) < std::extent<decltype(buffer_)>::value); 129*09537850SAkhilesh Sanikop return buffer_[plane]; 130*09537850SAkhilesh Sanikop } data(int plane)131*09537850SAkhilesh Sanikop const uint8_t* data(int plane) const { 132*09537850SAkhilesh Sanikop assert(plane >= 0); 133*09537850SAkhilesh Sanikop assert(static_cast<size_t>(plane) < std::extent<decltype(buffer_)>::value); 134*09537850SAkhilesh Sanikop return buffer_[plane]; 135*09537850SAkhilesh Sanikop } 136*09537850SAkhilesh Sanikop 137*09537850SAkhilesh Sanikop // Returns the stride in bytes for |plane|. stride(int plane)138*09537850SAkhilesh Sanikop int stride(int plane) const { 139*09537850SAkhilesh Sanikop assert(plane >= 0); 140*09537850SAkhilesh Sanikop assert(static_cast<size_t>(plane) < std::extent<decltype(stride_)>::value); 141*09537850SAkhilesh Sanikop return stride_[plane]; 142*09537850SAkhilesh Sanikop } 143*09537850SAkhilesh Sanikop // Restore the previous set of compiler warnings. 144*09537850SAkhilesh Sanikop #ifdef __GNUC__ 145*09537850SAkhilesh Sanikop #pragma GCC diagnostic pop 146*09537850SAkhilesh Sanikop #endif 147*09537850SAkhilesh Sanikop 148*09537850SAkhilesh Sanikop private: 149*09537850SAkhilesh Sanikop static constexpr int kFrameBufferRowAlignment = 16; 150*09537850SAkhilesh Sanikop 151*09537850SAkhilesh Sanikop #if LIBGAV1_MSAN 152*09537850SAkhilesh Sanikop void InitializeFrameBorders(); 153*09537850SAkhilesh Sanikop #endif 154*09537850SAkhilesh Sanikop 155*09537850SAkhilesh Sanikop int bitdepth_ = 0; 156*09537850SAkhilesh Sanikop bool is_monochrome_ = false; 157*09537850SAkhilesh Sanikop 158*09537850SAkhilesh Sanikop // y_width_ and y_height_ are the |width| and |height| arguments passed to the 159*09537850SAkhilesh Sanikop // Realloc() method. 160*09537850SAkhilesh Sanikop // 161*09537850SAkhilesh Sanikop // uv_width_ and uv_height_ are computed from y_width_ and y_height_ as 162*09537850SAkhilesh Sanikop // follows: 163*09537850SAkhilesh Sanikop // uv_width_ = (y_width_ + subsampling_x_) >> subsampling_x_ 164*09537850SAkhilesh Sanikop // uv_height_ = (y_height_ + subsampling_y_) >> subsampling_y_ 165*09537850SAkhilesh Sanikop int y_width_ = 0; 166*09537850SAkhilesh Sanikop int uv_width_ = 0; 167*09537850SAkhilesh Sanikop int y_height_ = 0; 168*09537850SAkhilesh Sanikop int uv_height_ = 0; 169*09537850SAkhilesh Sanikop 170*09537850SAkhilesh Sanikop int left_border_[kMaxPlanes] = {}; 171*09537850SAkhilesh Sanikop int right_border_[kMaxPlanes] = {}; 172*09537850SAkhilesh Sanikop int top_border_[kMaxPlanes] = {}; 173*09537850SAkhilesh Sanikop int bottom_border_[kMaxPlanes] = {}; 174*09537850SAkhilesh Sanikop 175*09537850SAkhilesh Sanikop int stride_[kMaxPlanes] = {}; 176*09537850SAkhilesh Sanikop uint8_t* buffer_[kMaxPlanes] = {}; 177*09537850SAkhilesh Sanikop 178*09537850SAkhilesh Sanikop // buffer_alloc_ and buffer_alloc_size_ are only used if the 179*09537850SAkhilesh Sanikop // get_frame_buffer callback is null and we allocate the buffer ourselves. 180*09537850SAkhilesh Sanikop std::unique_ptr<uint8_t[]> buffer_alloc_; 181*09537850SAkhilesh Sanikop size_t buffer_alloc_size_ = 0; 182*09537850SAkhilesh Sanikop 183*09537850SAkhilesh Sanikop int8_t subsampling_x_ = 0; // 0 or 1. 184*09537850SAkhilesh Sanikop int8_t subsampling_y_ = 0; // 0 or 1. 185*09537850SAkhilesh Sanikop }; 186*09537850SAkhilesh Sanikop 187*09537850SAkhilesh Sanikop } // namespace libgav1 188*09537850SAkhilesh Sanikop 189*09537850SAkhilesh Sanikop #endif // LIBGAV1_SRC_YUV_BUFFER_H_ 190