1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/yuv_buffer.h"
16
17 #include <cassert>
18 #include <cstddef>
19 #include <new>
20
21 #include "src/frame_buffer_utils.h"
22 #include "src/utils/common.h"
23 #include "src/utils/compiler_attributes.h"
24 #include "src/utils/logging.h"
25
26 namespace libgav1 {
27
28 // Size conventions:
29 // * Widths, heights, and border sizes are in pixels.
30 // * Strides and plane sizes are in bytes.
31 //
32 // YuvBuffer objects may be reused through the BufferPool. Realloc() must
33 // assume that data members (except buffer_alloc_ and buffer_alloc_size_) may
34 // contain stale values from the previous use, and must set all data members
35 // from scratch. In particular, Realloc() must not rely on the initial values
36 // of data members set by the YuvBuffer constructor.
Realloc(int bitdepth,bool is_monochrome,int width,int height,int8_t subsampling_x,int8_t subsampling_y,int left_border,int right_border,int top_border,int bottom_border,GetFrameBufferCallback get_frame_buffer,void * callback_private_data,void ** buffer_private_data)37 bool YuvBuffer::Realloc(int bitdepth, bool is_monochrome, int width, int height,
38 int8_t subsampling_x, int8_t subsampling_y,
39 int left_border, int right_border, int top_border,
40 int bottom_border,
41 GetFrameBufferCallback get_frame_buffer,
42 void* callback_private_data,
43 void** buffer_private_data) {
44 // Only support allocating buffers that have borders that are a multiple of
45 // 2. The border restriction is required because we may subsample the
46 // borders in the chroma planes.
47 if (((left_border | right_border | top_border | bottom_border) & 1) != 0) {
48 LIBGAV1_DLOG(ERROR,
49 "Borders must be a multiple of 2: left_border = %d, "
50 "right_border = %d, top_border = %d, bottom_border = %d.",
51 left_border, right_border, top_border, bottom_border);
52 return false;
53 }
54
55 // Every row in the plane buffers needs to be kFrameBufferRowAlignment-byte
56 // aligned. Since the strides are multiples of kFrameBufferRowAlignment bytes,
57 // it suffices to just make the plane buffers kFrameBufferRowAlignment-byte
58 // aligned.
59 const int plane_align = kFrameBufferRowAlignment;
60 const int uv_width =
61 is_monochrome ? 0 : SubsampledValue(width, subsampling_x);
62 const int uv_height =
63 is_monochrome ? 0 : SubsampledValue(height, subsampling_y);
64 const int uv_left_border = is_monochrome ? 0 : left_border >> subsampling_x;
65 const int uv_right_border = is_monochrome ? 0 : right_border >> subsampling_x;
66 const int uv_top_border = is_monochrome ? 0 : top_border >> subsampling_y;
67 const int uv_bottom_border =
68 is_monochrome ? 0 : bottom_border >> subsampling_y;
69
70 if (get_frame_buffer != nullptr) {
71 assert(buffer_private_data != nullptr);
72
73 const Libgav1ImageFormat image_format =
74 ComposeImageFormat(is_monochrome, subsampling_x, subsampling_y);
75 FrameBuffer frame_buffer;
76 if (get_frame_buffer(callback_private_data, bitdepth, image_format, width,
77 height, left_border, right_border, top_border,
78 bottom_border, kFrameBufferRowAlignment,
79 &frame_buffer) != kStatusOk) {
80 return false;
81 }
82
83 if (frame_buffer.plane[0] == nullptr ||
84 (!is_monochrome && frame_buffer.plane[1] == nullptr) ||
85 (!is_monochrome && frame_buffer.plane[2] == nullptr)) {
86 assert(false && "The get_frame_buffer callback malfunctioned.");
87 LIBGAV1_DLOG(ERROR, "The get_frame_buffer callback malfunctioned.");
88 return false;
89 }
90
91 stride_[kPlaneY] = frame_buffer.stride[0];
92 stride_[kPlaneU] = frame_buffer.stride[1];
93 stride_[kPlaneV] = frame_buffer.stride[2];
94 buffer_[kPlaneY] = frame_buffer.plane[0];
95 buffer_[kPlaneU] = frame_buffer.plane[1];
96 buffer_[kPlaneV] = frame_buffer.plane[2];
97 *buffer_private_data = frame_buffer.private_data;
98 } else {
99 assert(callback_private_data == nullptr);
100 assert(buffer_private_data == nullptr);
101
102 // Calculate y_stride (in bytes). It is padded to a multiple of
103 // kFrameBufferRowAlignment bytes.
104 int y_stride = width + left_border + right_border;
105 #if LIBGAV1_MAX_BITDEPTH >= 10
106 if (bitdepth > 8) y_stride *= sizeof(uint16_t);
107 #endif
108 y_stride = Align(y_stride, kFrameBufferRowAlignment);
109 // Size of the Y plane in bytes.
110 const uint64_t y_plane_size = (height + top_border + bottom_border) *
111 static_cast<uint64_t>(y_stride) +
112 (plane_align - 1);
113
114 // Calculate uv_stride (in bytes). It is padded to a multiple of
115 // kFrameBufferRowAlignment bytes.
116 int uv_stride = uv_width + uv_left_border + uv_right_border;
117 #if LIBGAV1_MAX_BITDEPTH >= 10
118 if (bitdepth > 8) uv_stride *= sizeof(uint16_t);
119 #endif
120 uv_stride = Align(uv_stride, kFrameBufferRowAlignment);
121 // Size of the U or V plane in bytes.
122 const uint64_t uv_plane_size =
123 is_monochrome ? 0
124 : (uv_height + uv_top_border + uv_bottom_border) *
125 static_cast<uint64_t>(uv_stride) +
126 (plane_align - 1);
127
128 // Allocate unaligned y_buffer, u_buffer, and v_buffer.
129 uint8_t* y_buffer = nullptr;
130 uint8_t* u_buffer = nullptr;
131 uint8_t* v_buffer = nullptr;
132
133 const uint64_t frame_size = y_plane_size + 2 * uv_plane_size;
134 if (frame_size > buffer_alloc_size_) {
135 // Allocation to hold larger frame, or first allocation.
136 if (frame_size != static_cast<size_t>(frame_size)) return false;
137
138 buffer_alloc_.reset(new (std::nothrow)
139 uint8_t[static_cast<size_t>(frame_size)]);
140 if (buffer_alloc_ == nullptr) {
141 buffer_alloc_size_ = 0;
142 return false;
143 }
144
145 buffer_alloc_size_ = static_cast<size_t>(frame_size);
146 }
147
148 y_buffer = buffer_alloc_.get();
149 if (!is_monochrome) {
150 u_buffer = y_buffer + y_plane_size;
151 v_buffer = u_buffer + uv_plane_size;
152 }
153
154 stride_[kPlaneY] = y_stride;
155 stride_[kPlaneU] = stride_[kPlaneV] = uv_stride;
156
157 int left_border_bytes = left_border;
158 int uv_left_border_bytes = uv_left_border;
159 #if LIBGAV1_MAX_BITDEPTH >= 10
160 if (bitdepth > 8) {
161 left_border_bytes *= sizeof(uint16_t);
162 uv_left_border_bytes *= sizeof(uint16_t);
163 }
164 #endif
165 buffer_[kPlaneY] = AlignAddr(
166 y_buffer + (top_border * y_stride) + left_border_bytes, plane_align);
167 buffer_[kPlaneU] =
168 AlignAddr(u_buffer + (uv_top_border * uv_stride) + uv_left_border_bytes,
169 plane_align);
170 buffer_[kPlaneV] =
171 AlignAddr(v_buffer + (uv_top_border * uv_stride) + uv_left_border_bytes,
172 plane_align);
173 }
174
175 y_width_ = width;
176 y_height_ = height;
177 left_border_[kPlaneY] = left_border;
178 right_border_[kPlaneY] = right_border;
179 top_border_[kPlaneY] = top_border;
180 bottom_border_[kPlaneY] = bottom_border;
181
182 uv_width_ = uv_width;
183 uv_height_ = uv_height;
184 left_border_[kPlaneU] = left_border_[kPlaneV] = uv_left_border;
185 right_border_[kPlaneU] = right_border_[kPlaneV] = uv_right_border;
186 top_border_[kPlaneU] = top_border_[kPlaneV] = uv_top_border;
187 bottom_border_[kPlaneU] = bottom_border_[kPlaneV] = uv_bottom_border;
188
189 subsampling_x_ = subsampling_x;
190 subsampling_y_ = subsampling_y;
191
192 bitdepth_ = bitdepth;
193 is_monochrome_ = is_monochrome;
194 assert(!is_monochrome || stride_[kPlaneU] == 0);
195 assert(!is_monochrome || stride_[kPlaneV] == 0);
196 assert(!is_monochrome || buffer_[kPlaneU] == nullptr);
197 assert(!is_monochrome || buffer_[kPlaneV] == nullptr);
198
199 #if LIBGAV1_MSAN
200 InitializeFrameBorders();
201 #endif
202
203 return true;
204 }
205
206 #if LIBGAV1_MSAN
InitializeFrameBorders()207 void YuvBuffer::InitializeFrameBorders() {
208 const int pixel_size = (bitdepth_ == 8) ? sizeof(uint8_t) : sizeof(uint16_t);
209 const int y_width_in_bytes = y_width_ * pixel_size;
210 // The optimized loop restoration code will overread the visible frame buffer
211 // into the right border. The optimized cfl subsambler uses the right border
212 // as well. Initialize the right border and padding to prevent msan warnings.
213 const int y_right_border_size_in_bytes = right_border_[kPlaneY] * pixel_size;
214 // Calculate the padding bytes for the buffer. Note: The stride of the buffer
215 // is always a multiple of 16. (see yuv_buffer.h)
216 const int y_right_padding_in_bytes =
217 stride_[kPlaneY] - (pixel_size * (y_width_ + left_border_[kPlaneY] +
218 right_border_[kPlaneY]));
219 const int y_padded_right_border_size =
220 y_right_border_size_in_bytes + y_right_padding_in_bytes;
221 constexpr uint8_t kRightValue = 0x55;
222 uint8_t* rb = buffer_[kPlaneY] + y_width_in_bytes;
223 for (int i = 0; i < y_height_ + bottom_border_[kPlaneY]; ++i) {
224 memset(rb, kRightValue, y_padded_right_border_size);
225 rb += stride_[kPlaneY];
226 }
227
228 if (!is_monochrome_) {
229 const int uv_width_in_bytes = uv_width_ * pixel_size;
230 const int uv_right_border_size_in_bytes =
231 right_border_[kPlaneU] * pixel_size;
232 assert(right_border_[kPlaneU] == right_border_[kPlaneV]);
233 const int u_right_padding_in_bytes =
234 stride_[kPlaneU] - (pixel_size * (uv_width_ + left_border_[kPlaneU] +
235 right_border_[kPlaneU]));
236 const int u_padded_right_border_size =
237 uv_right_border_size_in_bytes + u_right_padding_in_bytes;
238 rb = buffer_[kPlaneU] + uv_width_in_bytes;
239 for (int i = 0; i < uv_height_; ++i) {
240 memset(rb, kRightValue, u_padded_right_border_size);
241 rb += stride_[kPlaneU];
242 }
243 const int v_right_padding_in_bytes =
244 stride_[kPlaneV] -
245 ((uv_width_ + left_border_[kPlaneV] + right_border_[kPlaneV]) *
246 pixel_size);
247 const int v_padded_right_border_size =
248 uv_right_border_size_in_bytes + v_right_padding_in_bytes;
249 rb = buffer_[kPlaneV] + uv_width_in_bytes;
250 for (int i = 0; i < uv_height_; ++i) {
251 memset(rb, kRightValue, v_padded_right_border_size);
252 rb += stride_[kPlaneV];
253 }
254 }
255
256 // The optimized cfl subsampler will overread (to the right of the current
257 // block) into the uninitialized visible area. The cfl subsampler can overread
258 // into the bottom border as well. Initialize the both to quiet msan warnings.
259 uint8_t* y_visible = buffer_[kPlaneY];
260 for (int i = 0; i < y_height_ + bottom_border_[kPlaneY]; ++i) {
261 memset(y_visible, kRightValue, y_width_in_bytes);
262 y_visible += stride_[kPlaneY];
263 }
264 }
265 #endif // LIBGAV1_MSAN
266
267 } // namespace libgav1
268