1 // Copyright 2021 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/buffer_pool.h"
16
17 #include <climits>
18 #include <cstdint>
19 #include <memory>
20 #include <ostream>
21 #include <tuple>
22 #include <utility>
23
24 #include "gtest/gtest.h"
25 #include "src/frame_buffer_utils.h"
26 #include "src/gav1/decoder_buffer.h"
27 #include "src/gav1/frame_buffer.h"
28 #include "src/internal_frame_buffer_list.h"
29 #include "src/utils/constants.h"
30 #include "src/utils/types.h"
31 #include "src/yuv_buffer.h"
32
33 namespace libgav1 {
34 namespace {
35
TEST(BufferPoolTest,RefCountedBufferPtr)36 TEST(BufferPoolTest, RefCountedBufferPtr) {
37 InternalFrameBufferList buffer_list;
38 BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
39 GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
40 &buffer_list);
41 RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
42 EXPECT_NE(buffer_ptr, nullptr);
43 EXPECT_EQ(buffer_ptr.use_count(), 1);
44
45 RefCountedBufferPtr buffer_ptr2 = buffer_ptr;
46 RefCountedBufferPtr buffer_ptr3 = buffer_ptr;
47 EXPECT_EQ(buffer_ptr.use_count(), 3);
48 EXPECT_EQ(buffer_ptr2.use_count(), 3);
49 EXPECT_EQ(buffer_ptr3.use_count(), 3);
50
51 buffer_ptr2 = nullptr;
52 EXPECT_EQ(buffer_ptr.use_count(), 2);
53 EXPECT_EQ(buffer_ptr2.use_count(), 0);
54 EXPECT_EQ(buffer_ptr3.use_count(), 2);
55
56 RefCountedBufferPtr buffer_ptr4 = std::move(buffer_ptr);
57 EXPECT_EQ(buffer_ptr.use_count(), 0);
58 EXPECT_EQ(buffer_ptr2.use_count(), 0);
59 EXPECT_EQ(buffer_ptr3.use_count(), 2);
60 EXPECT_EQ(buffer_ptr4.use_count(), 2);
61 }
62
TEST(RefCountedBufferTest,SetFrameDimensions)63 TEST(RefCountedBufferTest, SetFrameDimensions) {
64 InternalFrameBufferList buffer_list;
65 BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
66 GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
67 &buffer_list);
68 RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
69 EXPECT_NE(buffer_ptr, nullptr);
70
71 // Test the undocumented default values of rows4x4() and columns4x4(). (Not
72 // sure if this is a good idea.)
73 EXPECT_EQ(buffer_ptr->rows4x4(), 0);
74 EXPECT_EQ(buffer_ptr->columns4x4(), 0);
75
76 // Test the side effects of SetFrameDimensions().
77 ObuFrameHeader frame_header = {};
78 frame_header.rows4x4 = 20;
79 frame_header.columns4x4 = 30;
80 EXPECT_TRUE(buffer_ptr->SetFrameDimensions(frame_header));
81 EXPECT_EQ(buffer_ptr->rows4x4(), 20);
82 EXPECT_EQ(buffer_ptr->columns4x4(), 30);
83 }
84
TEST(RefCountedBuffertTest,WaitUntil)85 TEST(RefCountedBuffertTest, WaitUntil) {
86 InternalFrameBufferList buffer_list;
87 BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
88 GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
89 &buffer_list);
90 RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
91 EXPECT_NE(buffer_ptr, nullptr);
92
93 int progress_row_cache;
94 buffer_ptr->SetProgress(10);
95 EXPECT_TRUE(buffer_ptr->WaitUntil(5, &progress_row_cache));
96 EXPECT_EQ(progress_row_cache, 10);
97
98 buffer_ptr->SetFrameState(kFrameStateDecoded);
99 EXPECT_TRUE(buffer_ptr->WaitUntil(500, &progress_row_cache));
100 EXPECT_EQ(progress_row_cache, INT_MAX);
101
102 buffer_ptr->Abort();
103 EXPECT_FALSE(buffer_ptr->WaitUntil(50, &progress_row_cache));
104 }
105
106 constexpr struct Params {
107 int width;
108 int height;
109 int8_t subsampling_x;
110 int8_t subsampling_y;
111 int border;
112 } kParams[] = {
113 {1920, 1080, 1, 1, 96}, //
114 {1920, 1080, 1, 1, 64}, //
115 {1920, 1080, 1, 1, 32}, //
116 {1920, 1080, 1, 1, 160}, //
117 {1920, 1080, 1, 0, 160}, //
118 {1920, 1080, 0, 0, 160}, //
119 };
120
operator <<(std::ostream & os,const Params & param)121 std::ostream& operator<<(std::ostream& os, const Params& param) {
122 return os << param.width << "x" << param.height
123 << ", subsampling(x/y): " << static_cast<int>(param.subsampling_x)
124 << "/" << static_cast<int>(param.subsampling_y)
125 << ", border: " << param.border;
126 }
127
128 class RefCountedBufferReallocTest
129 : public testing::TestWithParam<std::tuple<bool, Params>> {
130 protected:
131 const bool use_external_callbacks_ = std::get<0>(GetParam());
132 const Params& param_ = std::get<1>(GetParam());
133 };
134
135 TEST_P(RefCountedBufferReallocTest, 8Bit) {
136 InternalFrameBufferList buffer_list;
137 FrameBufferSizeChangedCallback on_frame_buffer_size_changed = nullptr;
138 GetFrameBufferCallback get_frame_buffer = nullptr;
139 ReleaseFrameBufferCallback release_frame_buffer = nullptr;
140 void* callback_private_data = nullptr;
141 if (use_external_callbacks_) {
142 on_frame_buffer_size_changed = OnInternalFrameBufferSizeChanged;
143 get_frame_buffer = GetInternalFrameBuffer;
144 release_frame_buffer = ReleaseInternalFrameBuffer;
145 callback_private_data = &buffer_list;
146 }
147
148 BufferPool buffer_pool(on_frame_buffer_size_changed, get_frame_buffer,
149 release_frame_buffer, callback_private_data);
150
151 RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
152 EXPECT_NE(buffer_ptr, nullptr);
153
154 const Libgav1ImageFormat image_format = ComposeImageFormat(
155 /*is_monochrome=*/false, param_.subsampling_x, param_.subsampling_y);
156 EXPECT_TRUE(buffer_pool.OnFrameBufferSizeChanged(
157 /*bitdepth=*/8, image_format, param_.width, param_.height, param_.border,
158 param_.border, param_.border, param_.border));
159
160 EXPECT_TRUE(buffer_ptr->Realloc(
161 /*bitdepth=*/8, /*is_monochrome=*/false, param_.width, param_.height,
162 param_.subsampling_x, param_.subsampling_y, param_.border, param_.border,
163 param_.border, param_.border));
164
165 // The first row of each plane is aligned at 16-byte boundaries.
166 EXPECT_EQ(
167 reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneY)) % 16, 0);
168 EXPECT_EQ(
169 reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneU)) % 16, 0);
170 EXPECT_EQ(
171 reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneV)) % 16, 0);
172
173 // Subsequent rows are aligned at 16-byte boundaries.
174 EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneY) % 16, 0);
175 EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneU) % 16, 0);
176 EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneV) % 16, 0);
177
178 // Check the borders.
179 EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneY), param_.border);
180 EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneY), param_.border);
181 EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneY), param_.border);
182 EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneY), param_.border);
183 EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneU),
184 param_.border >> param_.subsampling_x);
185 EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneU),
186 param_.border >> param_.subsampling_x);
187 EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneU),
188 param_.border >> param_.subsampling_y);
189 EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneU),
190 param_.border >> param_.subsampling_y);
191 EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneV),
192 param_.border >> param_.subsampling_x);
193 EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneV),
194 param_.border >> param_.subsampling_x);
195 EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneV),
196 param_.border >> param_.subsampling_y);
197 EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneV),
198 param_.border >> param_.subsampling_y);
199
200 // Write to the upper-left corner of the border.
201 uint8_t* y_buffer = buffer_ptr->buffer()->data(kPlaneY);
202 int y_stride = buffer_ptr->buffer()->stride(kPlaneY);
203 y_buffer[-buffer_ptr->buffer()->left_border(kPlaneY) -
204 buffer_ptr->buffer()->top_border(kPlaneY) * y_stride] = 0;
205 // Write to the lower-right corner of the border.
206 uint8_t* v_buffer = buffer_ptr->buffer()->data(kPlaneV);
207 int v_stride = buffer_ptr->buffer()->stride(kPlaneV);
208 v_buffer[(buffer_ptr->buffer()->height(kPlaneV) +
209 buffer_ptr->buffer()->bottom_border(kPlaneV) - 1) *
210 v_stride +
211 buffer_ptr->buffer()->width(kPlaneV) +
212 buffer_ptr->buffer()->right_border(kPlaneV) - 1] = 0;
213 }
214
215 #if LIBGAV1_MAX_BITDEPTH >= 10
216 TEST_P(RefCountedBufferReallocTest, 10Bit) {
217 InternalFrameBufferList buffer_list;
218 FrameBufferSizeChangedCallback on_frame_buffer_size_changed = nullptr;
219 GetFrameBufferCallback get_frame_buffer = nullptr;
220 ReleaseFrameBufferCallback release_frame_buffer = nullptr;
221 void* callback_private_data = nullptr;
222 if (use_external_callbacks_) {
223 on_frame_buffer_size_changed = OnInternalFrameBufferSizeChanged;
224 get_frame_buffer = GetInternalFrameBuffer;
225 release_frame_buffer = ReleaseInternalFrameBuffer;
226 callback_private_data = &buffer_list;
227 }
228
229 BufferPool buffer_pool(on_frame_buffer_size_changed, get_frame_buffer,
230 release_frame_buffer, callback_private_data);
231
232 RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
233 EXPECT_NE(buffer_ptr, nullptr);
234
235 const Libgav1ImageFormat image_format = ComposeImageFormat(
236 /*is_monochrome=*/false, param_.subsampling_x, param_.subsampling_y);
237 EXPECT_TRUE(buffer_pool.OnFrameBufferSizeChanged(
238 /*bitdepth=*/8, image_format, param_.width, param_.height, param_.border,
239 param_.border, param_.border, param_.border));
240
241 EXPECT_TRUE(buffer_ptr->Realloc(
242 /*bitdepth=*/10, /*is_monochrome=*/false, param_.width, param_.height,
243 param_.subsampling_x, param_.subsampling_y, param_.border, param_.border,
244 param_.border, param_.border));
245
246 // The first row of each plane is aligned at 16-byte boundaries.
247 EXPECT_EQ(
248 reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneY)) % 16, 0);
249 EXPECT_EQ(
250 reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneU)) % 16, 0);
251 EXPECT_EQ(
252 reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneV)) % 16, 0);
253
254 // Subsequent rows are aligned at 16-byte boundaries.
255 EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneY) % 16, 0);
256 EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneU) % 16, 0);
257 EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneV) % 16, 0);
258
259 // Check the borders.
260 EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneY), param_.border);
261 EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneY), param_.border);
262 EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneY), param_.border);
263 EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneY), param_.border);
264 EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneU),
265 param_.border >> param_.subsampling_x);
266 EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneU),
267 param_.border >> param_.subsampling_x);
268 EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneU),
269 param_.border >> param_.subsampling_y);
270 EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneU),
271 param_.border >> param_.subsampling_y);
272 EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneV),
273 param_.border >> param_.subsampling_x);
274 EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneV),
275 param_.border >> param_.subsampling_x);
276 EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneV),
277 param_.border >> param_.subsampling_y);
278 EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneV),
279 param_.border >> param_.subsampling_y);
280
281 // Write to the upper-left corner of the border.
282 auto* y_buffer =
283 reinterpret_cast<uint16_t*>(buffer_ptr->buffer()->data(kPlaneY));
284 int y_stride = buffer_ptr->buffer()->stride(kPlaneY) / sizeof(uint16_t);
285 y_buffer[-buffer_ptr->buffer()->left_border(kPlaneY) -
286 buffer_ptr->buffer()->top_border(kPlaneY) * y_stride] = 0;
287 // Write to the lower-right corner of the border.
288 auto* v_buffer =
289 reinterpret_cast<uint16_t*>(buffer_ptr->buffer()->data(kPlaneV));
290 int v_stride = buffer_ptr->buffer()->stride(kPlaneV) / sizeof(uint16_t);
291 v_buffer[(buffer_ptr->buffer()->height(kPlaneV) +
292 buffer_ptr->buffer()->bottom_border(kPlaneV) - 1) *
293 v_stride +
294 buffer_ptr->buffer()->width(kPlaneV) +
295 buffer_ptr->buffer()->right_border(kPlaneV) - 1] = 0;
296 }
297 #endif // LIBGAV1_MAX_BITDEPTH >= 10
298
299 INSTANTIATE_TEST_SUITE_P(
300 Default, RefCountedBufferReallocTest,
301 testing::Combine(testing::Bool(), // use_external_callbacks
302 testing::ValuesIn(kParams)));
303
304 } // namespace
305 } // namespace libgav1
306