aboutsummaryrefslogtreecommitdiff
path: root/src/buffer_pool_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer_pool_test.cc')
-rw-r--r--src/buffer_pool_test.cc305
1 files changed, 305 insertions, 0 deletions
diff --git a/src/buffer_pool_test.cc b/src/buffer_pool_test.cc
new file mode 100644
index 0000000..abe681e
--- /dev/null
+++ b/src/buffer_pool_test.cc
@@ -0,0 +1,305 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/buffer_pool.h"
+
+#include <climits>
+#include <cstdint>
+#include <memory>
+#include <ostream>
+#include <tuple>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/frame_buffer_utils.h"
+#include "src/gav1/decoder_buffer.h"
+#include "src/gav1/frame_buffer.h"
+#include "src/internal_frame_buffer_list.h"
+#include "src/utils/constants.h"
+#include "src/utils/types.h"
+#include "src/yuv_buffer.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(BufferPoolTest, RefCountedBufferPtr) {
+ InternalFrameBufferList buffer_list;
+ BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
+ GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
+ &buffer_list);
+ RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+ EXPECT_NE(buffer_ptr, nullptr);
+ EXPECT_EQ(buffer_ptr.use_count(), 1);
+
+ RefCountedBufferPtr buffer_ptr2 = buffer_ptr;
+ RefCountedBufferPtr buffer_ptr3 = buffer_ptr;
+ EXPECT_EQ(buffer_ptr.use_count(), 3);
+ EXPECT_EQ(buffer_ptr2.use_count(), 3);
+ EXPECT_EQ(buffer_ptr3.use_count(), 3);
+
+ buffer_ptr2 = nullptr;
+ EXPECT_EQ(buffer_ptr.use_count(), 2);
+ EXPECT_EQ(buffer_ptr2.use_count(), 0);
+ EXPECT_EQ(buffer_ptr3.use_count(), 2);
+
+ RefCountedBufferPtr buffer_ptr4 = std::move(buffer_ptr);
+ EXPECT_EQ(buffer_ptr.use_count(), 0);
+ EXPECT_EQ(buffer_ptr2.use_count(), 0);
+ EXPECT_EQ(buffer_ptr3.use_count(), 2);
+ EXPECT_EQ(buffer_ptr4.use_count(), 2);
+}
+
+TEST(RefCountedBufferTest, SetFrameDimensions) {
+ InternalFrameBufferList buffer_list;
+ BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
+ GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
+ &buffer_list);
+ RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+ EXPECT_NE(buffer_ptr, nullptr);
+
+ // Test the undocumented default values of rows4x4() and columns4x4(). (Not
+ // sure if this is a good idea.)
+ EXPECT_EQ(buffer_ptr->rows4x4(), 0);
+ EXPECT_EQ(buffer_ptr->columns4x4(), 0);
+
+ // Test the side effects of SetFrameDimensions().
+ ObuFrameHeader frame_header = {};
+ frame_header.rows4x4 = 20;
+ frame_header.columns4x4 = 30;
+ EXPECT_TRUE(buffer_ptr->SetFrameDimensions(frame_header));
+ EXPECT_EQ(buffer_ptr->rows4x4(), 20);
+ EXPECT_EQ(buffer_ptr->columns4x4(), 30);
+}
+
+TEST(RefCountedBuffertTest, WaitUntil) {
+ InternalFrameBufferList buffer_list;
+ BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
+ GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
+ &buffer_list);
+ RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+ EXPECT_NE(buffer_ptr, nullptr);
+
+ int progress_row_cache;
+ buffer_ptr->SetProgress(10);
+ EXPECT_TRUE(buffer_ptr->WaitUntil(5, &progress_row_cache));
+ EXPECT_EQ(progress_row_cache, 10);
+
+ buffer_ptr->SetFrameState(kFrameStateDecoded);
+ EXPECT_TRUE(buffer_ptr->WaitUntil(500, &progress_row_cache));
+ EXPECT_EQ(progress_row_cache, INT_MAX);
+
+ buffer_ptr->Abort();
+ EXPECT_FALSE(buffer_ptr->WaitUntil(50, &progress_row_cache));
+}
+
+constexpr struct Params {
+ int width;
+ int height;
+ int8_t subsampling_x;
+ int8_t subsampling_y;
+ int border;
+} kParams[] = {
+ {1920, 1080, 1, 1, 96}, //
+ {1920, 1080, 1, 1, 64}, //
+ {1920, 1080, 1, 1, 32}, //
+ {1920, 1080, 1, 1, 160}, //
+ {1920, 1080, 1, 0, 160}, //
+ {1920, 1080, 0, 0, 160}, //
+};
+
+std::ostream& operator<<(std::ostream& os, const Params& param) {
+ return os << param.width << "x" << param.height
+ << ", subsampling(x/y): " << static_cast<int>(param.subsampling_x)
+ << "/" << static_cast<int>(param.subsampling_y)
+ << ", border: " << param.border;
+}
+
+class RefCountedBufferReallocTest
+ : public testing::TestWithParam<std::tuple<bool, Params>> {
+ protected:
+ const bool use_external_callbacks_ = std::get<0>(GetParam());
+ const Params& param_ = std::get<1>(GetParam());
+};
+
+TEST_P(RefCountedBufferReallocTest, 8Bit) {
+ InternalFrameBufferList buffer_list;
+ FrameBufferSizeChangedCallback on_frame_buffer_size_changed = nullptr;
+ GetFrameBufferCallback get_frame_buffer = nullptr;
+ ReleaseFrameBufferCallback release_frame_buffer = nullptr;
+ void* callback_private_data = nullptr;
+ if (use_external_callbacks_) {
+ on_frame_buffer_size_changed = OnInternalFrameBufferSizeChanged;
+ get_frame_buffer = GetInternalFrameBuffer;
+ release_frame_buffer = ReleaseInternalFrameBuffer;
+ callback_private_data = &buffer_list;
+ }
+
+ BufferPool buffer_pool(on_frame_buffer_size_changed, get_frame_buffer,
+ release_frame_buffer, callback_private_data);
+
+ RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+ EXPECT_NE(buffer_ptr, nullptr);
+
+ const Libgav1ImageFormat image_format = ComposeImageFormat(
+ /*is_monochrome=*/false, param_.subsampling_x, param_.subsampling_y);
+ EXPECT_TRUE(buffer_pool.OnFrameBufferSizeChanged(
+ /*bitdepth=*/8, image_format, param_.width, param_.height, param_.border,
+ param_.border, param_.border, param_.border));
+
+ EXPECT_TRUE(buffer_ptr->Realloc(
+ /*bitdepth=*/8, /*is_monochrome=*/false, param_.width, param_.height,
+ param_.subsampling_x, param_.subsampling_y, param_.border, param_.border,
+ param_.border, param_.border));
+
+ // The first row of each plane is aligned at 16-byte boundaries.
+ EXPECT_EQ(
+ reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneY)) % 16, 0);
+ EXPECT_EQ(
+ reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneU)) % 16, 0);
+ EXPECT_EQ(
+ reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneV)) % 16, 0);
+
+ // Subsequent rows are aligned at 16-byte boundaries.
+ EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneY) % 16, 0);
+ EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneU) % 16, 0);
+ EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneV) % 16, 0);
+
+ // Check the borders.
+ EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneU),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneU),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneU),
+ param_.border >> param_.subsampling_y);
+ EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneU),
+ param_.border >> param_.subsampling_y);
+ EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneV),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneV),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneV),
+ param_.border >> param_.subsampling_y);
+ EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneV),
+ param_.border >> param_.subsampling_y);
+
+ // Write to the upper-left corner of the border.
+ uint8_t* y_buffer = buffer_ptr->buffer()->data(kPlaneY);
+ int y_stride = buffer_ptr->buffer()->stride(kPlaneY);
+ y_buffer[-buffer_ptr->buffer()->left_border(kPlaneY) -
+ buffer_ptr->buffer()->top_border(kPlaneY) * y_stride] = 0;
+ // Write to the lower-right corner of the border.
+ uint8_t* v_buffer = buffer_ptr->buffer()->data(kPlaneV);
+ int v_stride = buffer_ptr->buffer()->stride(kPlaneV);
+ v_buffer[(buffer_ptr->buffer()->height(kPlaneV) +
+ buffer_ptr->buffer()->bottom_border(kPlaneV) - 1) *
+ v_stride +
+ buffer_ptr->buffer()->width(kPlaneV) +
+ buffer_ptr->buffer()->right_border(kPlaneV) - 1] = 0;
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+TEST_P(RefCountedBufferReallocTest, 10Bit) {
+ InternalFrameBufferList buffer_list;
+ FrameBufferSizeChangedCallback on_frame_buffer_size_changed = nullptr;
+ GetFrameBufferCallback get_frame_buffer = nullptr;
+ ReleaseFrameBufferCallback release_frame_buffer = nullptr;
+ void* callback_private_data = nullptr;
+ if (use_external_callbacks_) {
+ on_frame_buffer_size_changed = OnInternalFrameBufferSizeChanged;
+ get_frame_buffer = GetInternalFrameBuffer;
+ release_frame_buffer = ReleaseInternalFrameBuffer;
+ callback_private_data = &buffer_list;
+ }
+
+ BufferPool buffer_pool(on_frame_buffer_size_changed, get_frame_buffer,
+ release_frame_buffer, callback_private_data);
+
+ RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+ EXPECT_NE(buffer_ptr, nullptr);
+
+ const Libgav1ImageFormat image_format = ComposeImageFormat(
+ /*is_monochrome=*/false, param_.subsampling_x, param_.subsampling_y);
+ EXPECT_TRUE(buffer_pool.OnFrameBufferSizeChanged(
+ /*bitdepth=*/8, image_format, param_.width, param_.height, param_.border,
+ param_.border, param_.border, param_.border));
+
+ EXPECT_TRUE(buffer_ptr->Realloc(
+ /*bitdepth=*/10, /*is_monochrome=*/false, param_.width, param_.height,
+ param_.subsampling_x, param_.subsampling_y, param_.border, param_.border,
+ param_.border, param_.border));
+
+ // The first row of each plane is aligned at 16-byte boundaries.
+ EXPECT_EQ(
+ reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneY)) % 16, 0);
+ EXPECT_EQ(
+ reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneU)) % 16, 0);
+ EXPECT_EQ(
+ reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneV)) % 16, 0);
+
+ // Subsequent rows are aligned at 16-byte boundaries.
+ EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneY) % 16, 0);
+ EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneU) % 16, 0);
+ EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneV) % 16, 0);
+
+ // Check the borders.
+ EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneY), param_.border);
+ EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneU),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneU),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneU),
+ param_.border >> param_.subsampling_y);
+ EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneU),
+ param_.border >> param_.subsampling_y);
+ EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneV),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneV),
+ param_.border >> param_.subsampling_x);
+ EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneV),
+ param_.border >> param_.subsampling_y);
+ EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneV),
+ param_.border >> param_.subsampling_y);
+
+ // Write to the upper-left corner of the border.
+ auto* y_buffer =
+ reinterpret_cast<uint16_t*>(buffer_ptr->buffer()->data(kPlaneY));
+ int y_stride = buffer_ptr->buffer()->stride(kPlaneY) / sizeof(uint16_t);
+ y_buffer[-buffer_ptr->buffer()->left_border(kPlaneY) -
+ buffer_ptr->buffer()->top_border(kPlaneY) * y_stride] = 0;
+ // Write to the lower-right corner of the border.
+ auto* v_buffer =
+ reinterpret_cast<uint16_t*>(buffer_ptr->buffer()->data(kPlaneV));
+ int v_stride = buffer_ptr->buffer()->stride(kPlaneV) / sizeof(uint16_t);
+ v_buffer[(buffer_ptr->buffer()->height(kPlaneV) +
+ buffer_ptr->buffer()->bottom_border(kPlaneV) - 1) *
+ v_stride +
+ buffer_ptr->buffer()->width(kPlaneV) +
+ buffer_ptr->buffer()->right_border(kPlaneV) - 1] = 0;
+}
+#endif // LIBGAV1_MAX_BITDEPTH >= 10
+
+INSTANTIATE_TEST_SUITE_P(
+ Default, RefCountedBufferReallocTest,
+ testing::Combine(testing::Bool(), // use_external_callbacks
+ testing::ValuesIn(kParams)));
+
+} // namespace
+} // namespace libgav1