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