1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
media / mojo / services / mojo_cdm_allocator_unittest.cc [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <cstring>
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "media/base/video_frame.h"
#include "media/cdm/api/content_decryption_module.h"
#include "media/cdm/cdm_helpers.h"
#include "media/mojo/services/mojo_cdm_allocator.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
namespace media {
class MojoCdmAllocatorTest : public testing::Test {
public:
MojoCdmAllocatorTest() = default;
MojoCdmAllocatorTest(const MojoCdmAllocatorTest&) = delete;
MojoCdmAllocatorTest& operator=(const MojoCdmAllocatorTest&) = delete;
~MojoCdmAllocatorTest() override = default;
protected:
cdm::Buffer* CreateCdmBuffer(size_t capacity) {
return allocator_.CreateCdmBuffer(capacity);
}
std::unique_ptr<VideoFrameImpl> CreateCdmVideoFrame() {
return allocator_.CreateCdmVideoFrame();
}
base::MappedReadOnlyRegion& GetRegion(cdm::Buffer* buffer) {
return allocator_.GetRegionForTesting(buffer);
}
size_t GetAvailableRegionCount() {
return allocator_.GetAvailableRegionCountForTesting();
}
private:
MojoCdmAllocator allocator_;
};
TEST_F(MojoCdmAllocatorTest, CreateCdmBuffer) {
cdm::Buffer* buffer = CreateCdmBuffer(100);
EXPECT_GE(buffer->Capacity(), 100u);
buffer->SetSize(50);
EXPECT_EQ(50u, buffer->Size());
buffer->Destroy();
}
TEST_F(MojoCdmAllocatorTest, ReuseCdmBuffer) {
const size_t kRandomDataSize = 46;
const char kTestData[] = "reduce reuse recycle";
// Create a small buffer.
cdm::Buffer* buffer = CreateCdmBuffer(kRandomDataSize);
{
// Create a mapping and write some test data.
auto& mapping = GetRegion(buffer).mapping;
// Note: deliberately using sizeof() to include the null terminator.
memcpy(mapping.memory(), kTestData, sizeof(kTestData));
}
buffer->Destroy();
// Now allocate a new buffer of the same size, it should reuse the one
// just freed.
cdm::Buffer* new_buffer = CreateCdmBuffer(kRandomDataSize);
{
auto& mapping = GetRegion(new_buffer).mapping;
// Check that the test data that was written there is still there as a proxy
// signal for checking that the shmem region is reused.
EXPECT_STREQ(kTestData, mapping.GetMemoryAs<char>());
}
new_buffer->Destroy();
}
TEST_F(MojoCdmAllocatorTest, MaxFreeBuffers) {
const size_t kMaxExpectedFreeBuffers = 3;
size_t buffer_size = 0;
const size_t kBufferSizeIncrease = 1000;
std::vector<cdm::Buffer*> buffers;
// Allocate and destroy 10 buffers in increasing size (to avoid buffer reuse).
// Eventually allocating a new buffer will free the smallest free buffer, so
// the number of free buffers will be capped at |kMaxExpectedFreeBuffers|.
for (int i = 0; i < 10; ++i) {
buffer_size += kBufferSizeIncrease;
cdm::Buffer* buffer = CreateCdmBuffer(buffer_size);
buffer->Destroy();
EXPECT_LE(GetAvailableRegionCount(), kMaxExpectedFreeBuffers);
}
}
TEST_F(MojoCdmAllocatorTest, CreateCdmVideoFrame) {
const int kWidth = 16;
const int kHeight = 9;
const VideoPixelFormat kFormat = PIXEL_FORMAT_I420;
const gfx::Size kSize(kWidth, kHeight);
const size_t kBufferSize = VideoFrame::AllocationSize(kFormat, kSize);
// Create a VideoFrameImpl and initialize it.
std::unique_ptr<VideoFrameImpl> video_frame = CreateCdmVideoFrame();
video_frame->SetFormat(cdm::kI420);
video_frame->SetSize({kWidth, kHeight});
video_frame->SetStride(
cdm::kYPlane, static_cast<uint32_t>(
VideoFrame::RowBytes(cdm::kYPlane, kFormat, kWidth)));
video_frame->SetStride(
cdm::kUPlane, static_cast<uint32_t>(
VideoFrame::RowBytes(cdm::kUPlane, kFormat, kWidth)));
video_frame->SetStride(
cdm::kVPlane, static_cast<uint32_t>(
VideoFrame::RowBytes(cdm::kVPlane, kFormat, kWidth)));
EXPECT_EQ(nullptr, video_frame->FrameBuffer());
// Now create a buffer to hold the frame and assign it to the VideoFrameImpl.
cdm::Buffer* buffer = CreateCdmBuffer(kBufferSize);
EXPECT_EQ(0u, GetAvailableRegionCount());
buffer->SetSize(static_cast<uint32_t>(kBufferSize));
video_frame->SetFrameBuffer(buffer);
EXPECT_NE(nullptr, video_frame->FrameBuffer());
// Transform it into a VideoFrame and make sure the buffer is no longer owned.
scoped_refptr<VideoFrame> frame = video_frame->TransformToVideoFrame(kSize);
EXPECT_EQ(nullptr, video_frame->FrameBuffer());
EXPECT_EQ(0u, GetAvailableRegionCount());
video_frame.reset();
// Check that the buffer is still in use. It will be freed when |frame|
// is destroyed.
EXPECT_EQ(0u, GetAvailableRegionCount());
frame = nullptr;
// Check that the buffer is now in the free list.
EXPECT_EQ(1u, GetAvailableRegionCount());
}
} // namespace media