Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool_unittest.cc
blobab3814aedf5bc48174b8f730eb6b4c6d84860d3c
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Unit test for VideoCaptureBufferPool.
7 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
9 #include "base/bind.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "cc/test/test_context_provider.h"
13 #include "cc/test/test_web_graphics_context_3d.h"
14 #include "content/browser/compositor/buffer_queue.h"
15 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
16 #include "content/browser/renderer_host/media/video_capture_controller.h"
17 #include "media/base/video_frame.h"
18 #include "media/base/video_util.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace content {
24 static const media::VideoPixelFormat kCaptureFormats[] = {
25 media::PIXEL_FORMAT_I420,
26 media::PIXEL_FORMAT_TEXTURE,
27 #if !defined(OS_ANDROID)
28 media::PIXEL_FORMAT_GPUMEMORYBUFFER
29 #endif
32 class VideoCaptureBufferPoolTest
33 : public testing::TestWithParam<media::VideoPixelFormat> {
34 protected:
35 // A GpuMemoryBuffer Mock to provide a trivial RGBA buffer as Map() backing.
36 // We need to allocate on ctor and deallocate on dtor so that consecutive
37 // Map()-Unmap() cycles yield the same underlying data pointer.
38 class MockGpuMemoryBuffer : public gfx::GpuMemoryBuffer {
39 public:
40 explicit MockGpuMemoryBuffer(const gfx::Size& size)
41 : size_(size), data_(new uint8[size_.GetArea() * 4]), mapped_(false) {}
42 ~MockGpuMemoryBuffer() override { delete[] data_; }
44 bool Map(void** data) override {
45 EXPECT_EQ(mapped_, false);
46 mapped_ = true;
47 data[0] = static_cast<void*>(data_);
48 return true;
50 void Unmap() override {
51 EXPECT_EQ(mapped_, true);
52 mapped_ = false;
54 bool IsMapped() const override { return mapped_; }
55 Format GetFormat() const override { return BGRA_8888; }
56 void GetStride(int* stride) const override {
57 *stride = size_.width() * 4;
58 return;
60 gfx::GpuMemoryBufferHandle GetHandle() const override {
61 return gfx::GpuMemoryBufferHandle();
63 ClientBuffer AsClientBuffer() override { return nullptr; }
65 private:
66 const gfx::Size size_;
67 uint8* const data_;
68 bool mapped_;
71 #if !defined(OS_ANDROID)
72 // The next two classes are needed to replicate the GpuMemoryBuffer allocation
73 // on Browser side.
74 class StubBrowserGpuMemoryBufferManager
75 : public BrowserGpuMemoryBufferManager {
76 public:
77 StubBrowserGpuMemoryBufferManager()
78 : BrowserGpuMemoryBufferManager(nullptr, 1) {}
80 scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
81 const gfx::Size& size,
82 gfx::GpuMemoryBuffer::Format format,
83 gfx::GpuMemoryBuffer::Usage usage) override {
84 return make_scoped_ptr(new MockGpuMemoryBuffer(size));
87 class MockBufferQueue : public BufferQueue {
88 public:
89 MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
90 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
91 unsigned int internalformat)
92 : BufferQueue(context_provider,
93 internalformat,
94 nullptr,
95 gpu_memory_buffer_manager,
96 1) {}
97 MOCK_METHOD4(CopyBufferDamage,
98 void(int, int, const gfx::Rect&, const gfx::Rect&));
100 #endif
102 // This is a generic Buffer tracker
103 class Buffer {
104 public:
105 Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
106 scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
107 int id)
108 : id_(id), pool_(pool), buffer_handle_(buffer_handle.Pass()) {}
109 ~Buffer() { pool_->RelinquishProducerReservation(id()); }
110 int id() const { return id_; }
111 size_t size() { return buffer_handle_->size(); }
112 void* data() { return buffer_handle_->data(); }
114 private:
115 const int id_;
116 const scoped_refptr<VideoCaptureBufferPool> pool_;
117 const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
120 VideoCaptureBufferPoolTest()
121 : expected_dropped_id_(0),
122 pool_(new VideoCaptureBufferPool(3)) {}
124 #if !defined(OS_ANDROID)
125 void SetUp() override {
126 scoped_refptr<cc::TestContextProvider> context_provider =
127 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
128 context_provider->BindToCurrentThread();
129 gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
130 output_surface_.reset(new MockBufferQueue(
131 context_provider, gpu_memory_buffer_manager_.get(), GL_RGBA));
132 output_surface_->Initialize();
134 #endif
136 void ExpectDroppedId(int expected_dropped_id) {
137 expected_dropped_id_ = expected_dropped_id;
140 scoped_ptr<Buffer> ReserveBuffer(const gfx::Size& dimensions,
141 media::VideoPixelFormat pixel_format) {
142 // To verify that ReserveBuffer always sets |buffer_id_to_drop|,
143 // initialize it to something different than the expected value.
144 int buffer_id_to_drop = ~expected_dropped_id_;
145 DVLOG(1) << media::VideoCaptureFormat::PixelFormatToString(pixel_format)
146 << " " << dimensions.ToString();
147 int buffer_id =
148 pool_->ReserveForProducer(pixel_format, dimensions, &buffer_id_to_drop);
149 if (buffer_id == VideoCaptureBufferPool::kInvalidId)
150 return scoped_ptr<Buffer>();
151 EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop);
153 scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle =
154 pool_->GetBufferHandle(buffer_id);
155 return scoped_ptr<Buffer>(
156 new Buffer(pool_, buffer_handle.Pass(), buffer_id));
159 int expected_dropped_id_;
160 scoped_refptr<VideoCaptureBufferPool> pool_;
162 private:
163 #if !defined(OS_ANDROID)
164 scoped_ptr<StubBrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
165 scoped_ptr<MockBufferQueue> output_surface_;
166 #endif
168 DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest);
171 TEST_P(VideoCaptureBufferPoolTest, BufferPool) {
172 const gfx::Size size_lo = gfx::Size(10, 10);
173 const gfx::Size size_hi = gfx::Size(21, 33);
174 const media::VideoCaptureFormat format_lo(size_lo, 0.0, GetParam());
175 const media::VideoCaptureFormat format_hi(size_hi, 0.0, GetParam());
177 // Reallocation won't happen for the first part of the test.
178 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
180 scoped_ptr<Buffer> buffer1 = ReserveBuffer(size_lo, GetParam());
181 ASSERT_NE(nullptr, buffer1.get());
182 ASSERT_LE(format_lo.ImageAllocationSize(), buffer1->size());
183 scoped_ptr<Buffer> buffer2 = ReserveBuffer(size_lo, GetParam());
184 ASSERT_NE(nullptr, buffer2.get());
185 ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
186 scoped_ptr<Buffer> buffer3 = ReserveBuffer(size_lo, GetParam());
187 ASSERT_NE(nullptr, buffer3.get());
188 ASSERT_LE(format_lo.ImageAllocationSize(), buffer3->size());
190 // Texture backed Frames cannot be manipulated via mapping.
191 if (GetParam() != media::PIXEL_FORMAT_TEXTURE) {
192 ASSERT_NE(nullptr, buffer1->data());
193 ASSERT_NE(nullptr, buffer2->data());
194 ASSERT_NE(nullptr, buffer3->data());
197 // Touch the memory.
198 if (buffer1->data() != nullptr)
199 memset(buffer1->data(), 0x11, buffer1->size());
200 if (buffer2->data() != nullptr)
201 memset(buffer2->data(), 0x44, buffer2->size());
202 if (buffer3->data() != nullptr)
203 memset(buffer3->data(), 0x77, buffer3->size());
205 // Fourth buffer should fail.
206 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
208 // Release 1st buffer and retry; this should succeed.
209 buffer1.reset();
210 scoped_ptr<Buffer> buffer4 = ReserveBuffer(size_lo, GetParam());
211 ASSERT_NE(nullptr, buffer4.get());
213 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
214 ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
216 // Validate the IDs
217 int buffer_id2 = buffer2->id();
218 ASSERT_EQ(1, buffer_id2);
219 const int buffer_id3 = buffer3->id();
220 ASSERT_EQ(2, buffer_id3);
221 const int buffer_id4 = buffer4->id();
222 ASSERT_EQ(0, buffer_id4);
223 void* const memory_pointer3 = buffer3->data();
225 // Deliver a buffer.
226 pool_->HoldForConsumers(buffer_id3, 2);
228 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
230 buffer3.reset(); // Old producer releases buffer. Should be a noop.
231 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
232 ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
234 buffer2.reset(); // Active producer releases buffer. Should free a buffer.
236 buffer1 = ReserveBuffer(size_lo, GetParam());
237 ASSERT_NE(nullptr, buffer1.get());
238 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
240 // First consumer finishes.
241 pool_->RelinquishConsumerHold(buffer_id3, 1);
242 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
244 // Second consumer finishes. This should free that buffer.
245 pool_->RelinquishConsumerHold(buffer_id3, 1);
246 buffer3 = ReserveBuffer(size_lo, GetParam());
247 ASSERT_NE(nullptr, buffer3.get());
248 ASSERT_EQ(buffer_id3, buffer3->id()) << "Buffer ID should be reused.";
249 ASSERT_EQ(memory_pointer3, buffer3->data());
250 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
252 // Now deliver & consume buffer1, but don't release the buffer.
253 int buffer_id1 = buffer1->id();
254 ASSERT_EQ(1, buffer_id1);
255 pool_->HoldForConsumers(buffer_id1, 5);
256 pool_->RelinquishConsumerHold(buffer_id1, 5);
258 // Even though the consumer is done with the buffer at |buffer_id1|, it cannot
259 // be re-allocated to the producer, because |buffer1| still references it. But
260 // when |buffer1| goes away, we should be able to re-reserve the buffer (and
261 // the ID ought to be the same).
262 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
263 buffer1.reset(); // Should free the buffer.
264 buffer2 = ReserveBuffer(size_lo, GetParam());
265 ASSERT_NE(nullptr, buffer2.get());
266 ASSERT_EQ(buffer_id1, buffer2->id());
267 buffer_id2 = buffer_id1;
268 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
270 // Now try reallocation with different resolutions. We expect reallocation
271 // to occur only when the old buffer is too small.
272 buffer2.reset();
273 ExpectDroppedId(buffer_id2);
274 buffer2 = ReserveBuffer(size_hi, GetParam());
275 ASSERT_NE(nullptr, buffer2.get());
276 ASSERT_LE(format_hi.ImageAllocationSize(), buffer2->size());
277 ASSERT_EQ(3, buffer2->id());
278 void* const memory_pointer_hi = buffer2->data();
279 buffer2.reset(); // Frees it.
280 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
281 buffer2 = ReserveBuffer(size_lo, GetParam());
282 void* const memory_pointer_lo = buffer2->data();
283 ASSERT_EQ(memory_pointer_hi, memory_pointer_lo)
284 << "Decrease in resolution should not reallocate buffer";
285 ASSERT_NE(nullptr, buffer2.get());
286 ASSERT_EQ(3, buffer2->id());
287 ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
288 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
290 // Tear down the pool_, writing into the buffers. The buffer should preserve
291 // the lifetime of the underlying memory.
292 buffer3.reset();
293 pool_ = NULL;
295 // Touch the memory.
296 if (buffer2->data() != nullptr)
297 memset(buffer2->data(), 0x22, buffer2->size());
298 if (buffer4->data() != nullptr)
299 memset(buffer4->data(), 0x55, buffer4->size());
300 buffer2.reset();
302 if (buffer4->data() != nullptr)
303 memset(buffer4->data(), 0x77, buffer4->size());
304 buffer4.reset();
307 INSTANTIATE_TEST_CASE_P(,
308 VideoCaptureBufferPoolTest,
309 testing::ValuesIn(kCaptureFormats));
311 } // namespace content