DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool_unittest.cc
blobe51eb794a6cda1b0f98a5f52ff2e2454aeea5c00
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 "base/message_loop/message_loop.h"
13 #include "cc/test/test_context_provider.h"
14 #include "cc/test/test_web_graphics_context_3d.h"
15 #include "content/browser/compositor/buffer_queue.h"
16 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
17 #include "content/browser/renderer_host/media/video_capture_controller.h"
18 #include "media/base/video_frame.h"
19 #include "media/base/video_util.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 namespace content {
25 struct PixelFormatAndStorage {
26 media::VideoPixelFormat pixel_format;
27 media::VideoPixelStorage pixel_storage;
30 static const PixelFormatAndStorage kCapturePixelFormatAndStorages[] = {
31 {media::PIXEL_FORMAT_I420, media::PIXEL_STORAGE_CPU},
32 {media::PIXEL_FORMAT_ARGB, media::PIXEL_STORAGE_CPU},
33 {media::PIXEL_FORMAT_ARGB, media::PIXEL_STORAGE_TEXTURE},
34 #if !defined(OS_ANDROID)
35 {media::PIXEL_FORMAT_I420, media::PIXEL_STORAGE_GPUMEMORYBUFFER},
36 {media::PIXEL_FORMAT_ARGB, media::PIXEL_STORAGE_GPUMEMORYBUFFER},
37 #endif
40 static const int kTestBufferPoolSize = 3;
42 class VideoCaptureBufferPoolTest
43 : public testing::TestWithParam<PixelFormatAndStorage> {
44 protected:
45 // A GpuMemoryBuffer Mock to provide a trivial RGBA buffer as Map() backing.
46 // We need to allocate on ctor and deallocate on dtor so that consecutive
47 // Map()-Unmap() cycles yield the same underlying data pointer.
48 class MockGpuMemoryBuffer : public gfx::GpuMemoryBuffer {
49 public:
50 explicit MockGpuMemoryBuffer(const gfx::Size& size)
51 : size_(size), data_(new uint8[size_.GetArea() * 4]), mapped_(false) {}
52 ~MockGpuMemoryBuffer() override { delete[] data_; }
54 bool Map(void** data) override {
55 EXPECT_EQ(mapped_, false);
56 mapped_ = true;
57 data[0] = static_cast<void*>(data_);
58 return true;
60 void Unmap() override {
61 EXPECT_EQ(mapped_, true);
62 mapped_ = false;
64 bool IsMapped() const override { return mapped_; }
65 Format GetFormat() const override { return BGRA_8888; }
66 void GetStride(int* stride) const override {
67 *stride = size_.width() * 4;
68 return;
70 gfx::GpuMemoryBufferHandle GetHandle() const override {
71 return gfx::GpuMemoryBufferHandle();
73 ClientBuffer AsClientBuffer() override { return nullptr; }
75 private:
76 const gfx::Size size_;
77 uint8* const data_;
78 bool mapped_;
81 #if !defined(OS_ANDROID)
82 // The next two classes are needed to replicate the GpuMemoryBuffer allocation
83 // on Browser side.
84 class StubBrowserGpuMemoryBufferManager
85 : public BrowserGpuMemoryBufferManager {
86 public:
87 StubBrowserGpuMemoryBufferManager() : BrowserGpuMemoryBufferManager(1) {}
89 scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
90 const gfx::Size& size,
91 gfx::GpuMemoryBuffer::Format format,
92 gfx::GpuMemoryBuffer::Usage usage) override {
93 return make_scoped_ptr(new MockGpuMemoryBuffer(size));
96 class MockBufferQueue : public BufferQueue {
97 public:
98 MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
99 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
100 unsigned int internalformat)
101 : BufferQueue(context_provider,
102 internalformat,
103 nullptr,
104 gpu_memory_buffer_manager,
105 1) {}
106 MOCK_METHOD4(CopyBufferDamage,
107 void(int, int, const gfx::Rect&, const gfx::Rect&));
109 #endif
111 // This is a generic Buffer tracker
112 class Buffer {
113 public:
114 Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
115 scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
116 int id)
117 : id_(id), pool_(pool), buffer_handle_(buffer_handle.Pass()) {}
118 ~Buffer() { pool_->RelinquishProducerReservation(id()); }
119 int id() const { return id_; }
120 size_t size() { return buffer_handle_->size(); }
121 void* data() { return buffer_handle_->data(); }
123 private:
124 const int id_;
125 const scoped_refptr<VideoCaptureBufferPool> pool_;
126 const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
129 VideoCaptureBufferPoolTest()
130 : expected_dropped_id_(0),
131 pool_(new VideoCaptureBufferPool(kTestBufferPoolSize)) {}
133 #if !defined(OS_ANDROID)
134 void SetUp() override {
135 scoped_refptr<cc::TestContextProvider> context_provider =
136 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
137 context_provider->BindToCurrentThread();
138 gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
139 output_surface_.reset(new MockBufferQueue(
140 context_provider, gpu_memory_buffer_manager_.get(), GL_RGBA));
141 output_surface_->Initialize();
143 #endif
145 void ExpectDroppedId(int expected_dropped_id) {
146 expected_dropped_id_ = expected_dropped_id;
149 scoped_ptr<Buffer> ReserveBuffer(const gfx::Size& dimensions,
150 PixelFormatAndStorage format_and_storage) {
151 // To verify that ReserveBuffer always sets |buffer_id_to_drop|,
152 // initialize it to something different than the expected value.
153 int buffer_id_to_drop = ~expected_dropped_id_;
154 DVLOG(1) << media::VideoCaptureFormat::PixelStorageToString(
155 format_and_storage.pixel_storage) << " "
156 << media::VideoCaptureFormat::PixelFormatToString(
157 format_and_storage.pixel_format) << " "
158 << dimensions.ToString();
159 const int buffer_id = pool_->ReserveForProducer(
160 format_and_storage.pixel_format, format_and_storage.pixel_storage,
161 dimensions, &buffer_id_to_drop);
162 if (buffer_id == VideoCaptureBufferPool::kInvalidId)
163 return scoped_ptr<Buffer>();
164 EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop);
166 scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle =
167 pool_->GetBufferHandle(buffer_id);
168 return scoped_ptr<Buffer>(
169 new Buffer(pool_, buffer_handle.Pass(), buffer_id));
172 base::MessageLoop loop_;
173 int expected_dropped_id_;
174 scoped_refptr<VideoCaptureBufferPool> pool_;
176 private:
177 #if !defined(OS_ANDROID)
178 scoped_ptr<StubBrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
179 scoped_ptr<MockBufferQueue> output_surface_;
180 #endif
182 DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest);
185 TEST_P(VideoCaptureBufferPoolTest, BufferPool) {
186 const gfx::Size size_lo = gfx::Size(10, 10);
187 const gfx::Size size_hi = gfx::Size(21, 33);
188 const media::VideoCaptureFormat format_lo(
189 size_lo, 0.0, GetParam().pixel_format, GetParam().pixel_storage);
190 const media::VideoCaptureFormat format_hi(
191 size_hi, 0.0, GetParam().pixel_format, GetParam().pixel_storage);
193 // Reallocation won't happen for the first part of the test.
194 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
196 // The buffer pool should have zero utilization before any buffers have been
197 // reserved.
198 ASSERT_EQ(0.0, pool_->GetBufferPoolUtilization());
200 scoped_ptr<Buffer> buffer1 = ReserveBuffer(size_lo, GetParam());
201 ASSERT_NE(nullptr, buffer1.get());
202 ASSERT_LE(format_lo.ImageAllocationSize(), buffer1->size());
203 ASSERT_EQ(1.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
204 scoped_ptr<Buffer> buffer2 = ReserveBuffer(size_lo, GetParam());
205 ASSERT_NE(nullptr, buffer2.get());
206 ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
207 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
208 scoped_ptr<Buffer> buffer3 = ReserveBuffer(size_lo, GetParam());
209 ASSERT_NE(nullptr, buffer3.get());
210 ASSERT_LE(format_lo.ImageAllocationSize(), buffer3->size());
211 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
213 // Texture backed Frames cannot be manipulated via mapping.
214 if (GetParam().pixel_storage != media::PIXEL_STORAGE_TEXTURE) {
215 ASSERT_NE(nullptr, buffer1->data());
216 ASSERT_NE(nullptr, buffer2->data());
217 ASSERT_NE(nullptr, buffer3->data());
220 // Touch the memory.
221 if (buffer1->data() != nullptr)
222 memset(buffer1->data(), 0x11, buffer1->size());
223 if (buffer2->data() != nullptr)
224 memset(buffer2->data(), 0x44, buffer2->size());
225 if (buffer3->data() != nullptr)
226 memset(buffer3->data(), 0x77, buffer3->size());
228 // Fourth buffer should fail. Buffer pool utilization should be at 100%.
229 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
230 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
232 // Release 1st buffer and retry; this should succeed.
233 buffer1.reset();
234 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
235 scoped_ptr<Buffer> buffer4 = ReserveBuffer(size_lo, GetParam());
236 ASSERT_NE(nullptr, buffer4.get());
237 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
239 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
240 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
241 ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
242 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
244 // Validate the IDs
245 int buffer_id2 = buffer2->id();
246 ASSERT_EQ(1, buffer_id2);
247 const int buffer_id3 = buffer3->id();
248 ASSERT_EQ(2, buffer_id3);
249 const int buffer_id4 = buffer4->id();
250 ASSERT_EQ(0, buffer_id4);
251 void* const memory_pointer3 = buffer3->data();
253 // Deliver a buffer.
254 pool_->HoldForConsumers(buffer_id3, 2);
256 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
257 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
259 buffer3.reset(); // Old producer releases buffer. Should be a noop.
260 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
261 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
262 ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
263 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
265 buffer2.reset(); // Active producer releases buffer. Should free a buffer.
267 buffer1 = ReserveBuffer(size_lo, GetParam());
268 ASSERT_NE(nullptr, buffer1.get());
269 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
270 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
271 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
273 // First consumer finishes.
274 pool_->RelinquishConsumerHold(buffer_id3, 1);
275 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
276 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
278 // Second consumer finishes. This should free that buffer.
279 pool_->RelinquishConsumerHold(buffer_id3, 1);
280 buffer3 = ReserveBuffer(size_lo, GetParam());
281 ASSERT_NE(nullptr, buffer3.get());
282 ASSERT_EQ(buffer_id3, buffer3->id()) << "Buffer ID should be reused.";
283 ASSERT_EQ(memory_pointer3, buffer3->data());
284 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
285 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
286 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
288 // Now deliver & consume buffer1, but don't release the buffer.
289 int buffer_id1 = buffer1->id();
290 ASSERT_EQ(1, buffer_id1);
291 pool_->HoldForConsumers(buffer_id1, 5);
292 pool_->RelinquishConsumerHold(buffer_id1, 5);
294 // Even though the consumer is done with the buffer at |buffer_id1|, it cannot
295 // be re-allocated to the producer, because |buffer1| still references it. But
296 // when |buffer1| goes away, we should be able to re-reserve the buffer (and
297 // the ID ought to be the same).
298 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
299 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
300 buffer1.reset(); // Should free the buffer.
301 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
302 buffer2 = ReserveBuffer(size_lo, GetParam());
303 ASSERT_NE(nullptr, buffer2.get());
304 ASSERT_EQ(buffer_id1, buffer2->id());
305 buffer_id2 = buffer_id1;
306 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
307 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
308 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
310 // Now try reallocation with different resolutions. We expect reallocation
311 // to occur only when the old buffer is too small.
312 buffer2.reset();
313 ExpectDroppedId(buffer_id2);
314 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
315 buffer2 = ReserveBuffer(size_hi, GetParam());
316 ASSERT_NE(nullptr, buffer2.get());
317 ASSERT_LE(format_hi.ImageAllocationSize(), buffer2->size());
318 ASSERT_EQ(3, buffer2->id());
319 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
320 void* const memory_pointer_hi = buffer2->data();
321 buffer2.reset(); // Frees it.
322 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
323 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
324 buffer2 = ReserveBuffer(size_lo, GetParam());
325 void* const memory_pointer_lo = buffer2->data();
326 ASSERT_EQ(memory_pointer_hi, memory_pointer_lo)
327 << "Decrease in resolution should not reallocate buffer";
328 ASSERT_NE(nullptr, buffer2.get());
329 ASSERT_EQ(3, buffer2->id());
330 ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
331 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
332 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
333 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
335 // Tear down the pool_, writing into the buffers. The buffer should preserve
336 // the lifetime of the underlying memory.
337 buffer3.reset();
338 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
339 pool_ = NULL;
341 // Touch the memory.
342 if (buffer2->data() != nullptr)
343 memset(buffer2->data(), 0x22, buffer2->size());
344 if (buffer4->data() != nullptr)
345 memset(buffer4->data(), 0x55, buffer4->size());
346 buffer2.reset();
348 if (buffer4->data() != nullptr)
349 memset(buffer4->data(), 0x77, buffer4->size());
350 buffer4.reset();
353 INSTANTIATE_TEST_CASE_P(,
354 VideoCaptureBufferPoolTest,
355 testing::ValuesIn(kCapturePixelFormatAndStorages));
357 } // namespace content