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