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