Add ICU message format support
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool_unittest.cc
bloba02aa931fc1fe694b76cd43047817d85d31053ca
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 gfx::BufferFormat GetFormat() const override {
68 return gfx::BufferFormat::BGRA_8888;
70 void GetStride(int* stride) const override {
71 *stride = size_.width() * 4;
72 return;
74 gfx::GpuMemoryBufferId GetId() const override { return 0; }
75 gfx::GpuMemoryBufferHandle GetHandle() const override {
76 return gfx::GpuMemoryBufferHandle();
78 ClientBuffer AsClientBuffer() override { return nullptr; }
80 private:
81 const gfx::Size size_;
82 uint8* const data_;
83 bool mapped_;
86 #if !defined(OS_ANDROID)
87 // The next two classes are needed to replicate the GpuMemoryBuffer allocation
88 // on Browser side.
89 class StubBrowserGpuMemoryBufferManager
90 : public BrowserGpuMemoryBufferManager {
91 public:
92 StubBrowserGpuMemoryBufferManager() : BrowserGpuMemoryBufferManager(1, 1) {}
94 scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
95 const gfx::Size& size,
96 gfx::BufferFormat format,
97 gfx::BufferUsage usage) override {
98 return make_scoped_ptr(new MockGpuMemoryBuffer(size));
101 class MockBufferQueue : public BufferQueue {
102 public:
103 MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
104 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
105 unsigned int target,
106 unsigned int internalformat)
107 : BufferQueue(context_provider,
108 target,
109 internalformat,
110 nullptr,
111 gpu_memory_buffer_manager,
112 1) {}
113 MOCK_METHOD4(CopyBufferDamage,
114 void(int, int, const gfx::Rect&, const gfx::Rect&));
116 #endif
118 // This is a generic Buffer tracker
119 class Buffer {
120 public:
121 Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
122 scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
123 int id)
124 : id_(id), pool_(pool), buffer_handle_(buffer_handle.Pass()) {}
125 ~Buffer() { pool_->RelinquishProducerReservation(id()); }
126 int id() const { return id_; }
127 size_t size() { return buffer_handle_->size(); }
128 void* data() { return buffer_handle_->data(); }
130 private:
131 const int id_;
132 const scoped_refptr<VideoCaptureBufferPool> pool_;
133 const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
136 VideoCaptureBufferPoolTest()
137 : expected_dropped_id_(0),
138 pool_(new VideoCaptureBufferPool(kTestBufferPoolSize)) {}
140 #if !defined(OS_ANDROID)
141 void SetUp() override {
142 scoped_refptr<cc::TestContextProvider> context_provider =
143 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
144 context_provider->BindToCurrentThread();
145 gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
146 output_surface_.reset(new MockBufferQueue(context_provider,
147 gpu_memory_buffer_manager_.get(),
148 GL_TEXTURE_2D, GL_RGBA));
149 output_surface_->Initialize();
151 #endif
153 void ExpectDroppedId(int expected_dropped_id) {
154 expected_dropped_id_ = expected_dropped_id;
157 scoped_ptr<Buffer> ReserveBuffer(const gfx::Size& dimensions,
158 PixelFormatAndStorage format_and_storage) {
159 // To verify that ReserveBuffer always sets |buffer_id_to_drop|,
160 // initialize it to something different than the expected value.
161 int buffer_id_to_drop = ~expected_dropped_id_;
162 DVLOG(1) << media::VideoCaptureFormat::PixelStorageToString(
163 format_and_storage.pixel_storage) << " "
164 << media::VideoCaptureFormat::PixelFormatToString(
165 format_and_storage.pixel_format) << " "
166 << dimensions.ToString();
167 const int buffer_id = pool_->ReserveForProducer(
168 format_and_storage.pixel_format, format_and_storage.pixel_storage,
169 dimensions, &buffer_id_to_drop);
170 if (buffer_id == VideoCaptureBufferPool::kInvalidId)
171 return scoped_ptr<Buffer>();
172 EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop);
174 scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle =
175 pool_->GetBufferHandle(buffer_id);
176 return scoped_ptr<Buffer>(
177 new Buffer(pool_, buffer_handle.Pass(), buffer_id));
180 base::MessageLoop loop_;
181 int expected_dropped_id_;
182 scoped_refptr<VideoCaptureBufferPool> pool_;
184 private:
185 #if !defined(OS_ANDROID)
186 scoped_ptr<StubBrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
187 scoped_ptr<MockBufferQueue> output_surface_;
188 #endif
190 DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest);
193 TEST_P(VideoCaptureBufferPoolTest, BufferPool) {
194 const gfx::Size size_lo = gfx::Size(10, 10);
195 const gfx::Size size_hi = gfx::Size(21, 33);
196 const media::VideoCaptureFormat format_lo(
197 size_lo, 0.0, GetParam().pixel_format, GetParam().pixel_storage);
198 const media::VideoCaptureFormat format_hi(
199 size_hi, 0.0, GetParam().pixel_format, GetParam().pixel_storage);
201 // Reallocation won't happen for the first part of the test.
202 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
204 // The buffer pool should have zero utilization before any buffers have been
205 // reserved.
206 ASSERT_EQ(0.0, pool_->GetBufferPoolUtilization());
208 scoped_ptr<Buffer> buffer1 = ReserveBuffer(size_lo, GetParam());
209 ASSERT_NE(nullptr, buffer1.get());
210 ASSERT_LE(format_lo.ImageAllocationSize(), buffer1->size());
211 ASSERT_EQ(1.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
212 scoped_ptr<Buffer> buffer2 = ReserveBuffer(size_lo, GetParam());
213 ASSERT_NE(nullptr, buffer2.get());
214 ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
215 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
216 scoped_ptr<Buffer> buffer3 = ReserveBuffer(size_lo, GetParam());
217 ASSERT_NE(nullptr, buffer3.get());
218 ASSERT_LE(format_lo.ImageAllocationSize(), buffer3->size());
219 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
221 // Texture backed Frames cannot be manipulated via mapping.
222 if (GetParam().pixel_storage != media::PIXEL_STORAGE_TEXTURE) {
223 ASSERT_NE(nullptr, buffer1->data());
224 ASSERT_NE(nullptr, buffer2->data());
225 ASSERT_NE(nullptr, buffer3->data());
228 // Touch the memory.
229 if (buffer1->data() != nullptr)
230 memset(buffer1->data(), 0x11, buffer1->size());
231 if (buffer2->data() != nullptr)
232 memset(buffer2->data(), 0x44, buffer2->size());
233 if (buffer3->data() != nullptr)
234 memset(buffer3->data(), 0x77, buffer3->size());
236 // Fourth buffer should fail. Buffer pool utilization should be at 100%.
237 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
238 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
240 // Release 1st buffer and retry; this should succeed.
241 buffer1.reset();
242 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
243 scoped_ptr<Buffer> buffer4 = ReserveBuffer(size_lo, GetParam());
244 ASSERT_NE(nullptr, buffer4.get());
245 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
247 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
248 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
249 ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
250 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
252 // Validate the IDs
253 int buffer_id2 = buffer2->id();
254 ASSERT_EQ(1, buffer_id2);
255 const int buffer_id3 = buffer3->id();
256 ASSERT_EQ(2, buffer_id3);
257 const int buffer_id4 = buffer4->id();
258 ASSERT_EQ(0, buffer_id4);
259 void* const memory_pointer3 = buffer3->data();
261 // Deliver a buffer.
262 pool_->HoldForConsumers(buffer_id3, 2);
264 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
265 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
267 buffer3.reset(); // Old producer releases buffer. Should be a noop.
268 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
269 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
270 ASSERT_FALSE(ReserveBuffer(size_hi, GetParam())) << "Pool should be empty";
271 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
273 buffer2.reset(); // Active producer releases buffer. Should free a buffer.
275 buffer1 = ReserveBuffer(size_lo, GetParam());
276 ASSERT_NE(nullptr, buffer1.get());
277 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
278 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
279 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
281 // First consumer finishes.
282 pool_->RelinquishConsumerHold(buffer_id3, 1);
283 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
284 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
286 // Second consumer finishes. This should free that buffer.
287 pool_->RelinquishConsumerHold(buffer_id3, 1);
288 buffer3 = ReserveBuffer(size_lo, GetParam());
289 ASSERT_NE(nullptr, buffer3.get());
290 ASSERT_EQ(buffer_id3, buffer3->id()) << "Buffer ID should be reused.";
291 ASSERT_EQ(memory_pointer3, buffer3->data());
292 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
293 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
294 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
296 // Now deliver & consume buffer1, but don't release the buffer.
297 int buffer_id1 = buffer1->id();
298 ASSERT_EQ(1, buffer_id1);
299 pool_->HoldForConsumers(buffer_id1, 5);
300 pool_->RelinquishConsumerHold(buffer_id1, 5);
302 // Even though the consumer is done with the buffer at |buffer_id1|, it cannot
303 // be re-allocated to the producer, because |buffer1| still references it. But
304 // when |buffer1| goes away, we should be able to re-reserve the buffer (and
305 // the ID ought to be the same).
306 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
307 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
308 buffer1.reset(); // Should free the buffer.
309 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
310 buffer2 = ReserveBuffer(size_lo, GetParam());
311 ASSERT_NE(nullptr, buffer2.get());
312 ASSERT_EQ(buffer_id1, buffer2->id());
313 buffer_id2 = buffer_id1;
314 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
315 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
316 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
318 // Now try reallocation with different resolutions. We expect reallocation
319 // to occur only when the old buffer is too small.
320 buffer2.reset();
321 ExpectDroppedId(buffer_id2);
322 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
323 buffer2 = ReserveBuffer(size_hi, GetParam());
324 ASSERT_NE(nullptr, buffer2.get());
325 ASSERT_LE(format_hi.ImageAllocationSize(), buffer2->size());
326 ASSERT_EQ(3, buffer2->id());
327 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
328 void* const memory_pointer_hi = buffer2->data();
329 buffer2.reset(); // Frees it.
330 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
331 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
332 buffer2 = ReserveBuffer(size_lo, GetParam());
333 void* const memory_pointer_lo = buffer2->data();
334 ASSERT_EQ(memory_pointer_hi, memory_pointer_lo)
335 << "Decrease in resolution should not reallocate buffer";
336 ASSERT_NE(nullptr, buffer2.get());
337 ASSERT_EQ(3, buffer2->id());
338 ASSERT_LE(format_lo.ImageAllocationSize(), buffer2->size());
339 ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
340 ASSERT_FALSE(ReserveBuffer(size_lo, GetParam())) << "Pool should be empty";
341 ASSERT_EQ(1.0, pool_->GetBufferPoolUtilization());
343 // Tear down the pool_, writing into the buffers. The buffer should preserve
344 // the lifetime of the underlying memory.
345 buffer3.reset();
346 ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
347 pool_ = NULL;
349 // Touch the memory.
350 if (buffer2->data() != nullptr)
351 memset(buffer2->data(), 0x22, buffer2->size());
352 if (buffer4->data() != nullptr)
353 memset(buffer4->data(), 0x55, buffer4->size());
354 buffer2.reset();
356 if (buffer4->data() != nullptr)
357 memset(buffer4->data(), 0x77, buffer4->size());
358 buffer4.reset();
361 INSTANTIATE_TEST_CASE_P(,
362 VideoCaptureBufferPoolTest,
363 testing::ValuesIn(kCapturePixelFormatAndStorages));
365 } // namespace content