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"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "content/browser/renderer_host/media/video_capture_controller.h"
13 #include "media/base/video_frame.h"
14 #include "media/base/video_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
19 class VideoCaptureBufferPoolTest
: public testing::Test
{
23 Buffer(const scoped_refptr
<VideoCaptureBufferPool
> pool
,
27 : pool_(pool
), id_(id
), data_(data
), size_(size
) {}
28 ~Buffer() { pool_
->RelinquishProducerReservation(id()); }
29 int id() const { return id_
; }
30 void* data() const { return data_
; }
31 size_t size() const { return size_
; }
34 const scoped_refptr
<VideoCaptureBufferPool
> pool_
;
39 VideoCaptureBufferPoolTest()
40 : expected_dropped_id_(0),
41 pool_(new VideoCaptureBufferPool(3)) {}
43 void ExpectDroppedId(int expected_dropped_id
) {
44 expected_dropped_id_
= expected_dropped_id
;
47 scoped_ptr
<Buffer
> ReserveI420Buffer(const gfx::Size
& dimensions
) {
48 const size_t frame_bytes
=
49 media::VideoFrame::AllocationSize(media::VideoFrame::I420
, dimensions
);
50 // To verify that ReserveI420Buffer always sets |buffer_id_to_drop|,
51 // initialize it to something different than the expected value.
52 int buffer_id_to_drop
= ~expected_dropped_id_
;
53 int buffer_id
= pool_
->ReserveForProducer(frame_bytes
, &buffer_id_to_drop
);
54 if (buffer_id
== VideoCaptureBufferPool::kInvalidId
)
55 return scoped_ptr
<Buffer
>();
59 pool_
->GetBufferInfo(buffer_id
, &memory
, &size
);
60 EXPECT_EQ(expected_dropped_id_
, buffer_id_to_drop
);
61 return scoped_ptr
<Buffer
>(new Buffer(pool_
, buffer_id
, memory
, size
));
64 int expected_dropped_id_
;
65 scoped_refptr
<VideoCaptureBufferPool
> pool_
;
68 DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest
);
71 TEST_F(VideoCaptureBufferPoolTest
, BufferPool
) {
72 const gfx::Size size_lo
= gfx::Size(640, 480);
73 const gfx::Size size_hi
= gfx::Size(1024, 768);
74 scoped_refptr
<media::VideoFrame
> non_pool_frame
=
75 media::VideoFrame::CreateFrame(media::VideoFrame::YV12
, size_lo
,
76 gfx::Rect(size_lo
), size_lo
,
79 // Reallocation won't happen for the first part of the test.
80 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId
);
82 scoped_ptr
<Buffer
> buffer1
= ReserveI420Buffer(size_lo
);
83 ASSERT_TRUE(NULL
!= buffer1
.get());
84 ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420
, size_lo
),
86 scoped_ptr
<Buffer
> buffer2
= ReserveI420Buffer(size_lo
);
87 ASSERT_TRUE(NULL
!= buffer2
.get());
88 ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420
, size_lo
),
90 scoped_ptr
<Buffer
> buffer3
= ReserveI420Buffer(size_lo
);
91 ASSERT_TRUE(NULL
!= buffer3
.get());
92 ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420
, size_lo
),
96 memset(buffer1
->data(), 0x11, buffer1
->size());
97 memset(buffer2
->data(), 0x44, buffer2
->size());
98 memset(buffer3
->data(), 0x77, buffer3
->size());
100 // Fourth buffer should fail.
101 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
103 // Release 1st buffer and retry; this should succeed.
105 scoped_ptr
<Buffer
> buffer4
= ReserveI420Buffer(size_lo
);
106 ASSERT_TRUE(NULL
!= buffer4
.get());
108 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
109 ASSERT_FALSE(ReserveI420Buffer(size_hi
)) << "Pool should be empty";
112 int buffer_id2
= buffer2
->id();
113 ASSERT_EQ(1, buffer_id2
);
114 int buffer_id3
= buffer3
->id();
115 ASSERT_EQ(2, buffer_id3
);
116 void* const memory_pointer3
= buffer3
->data();
117 int buffer_id4
= buffer4
->id();
118 ASSERT_EQ(0, buffer_id4
);
121 pool_
->HoldForConsumers(buffer_id3
, 2);
123 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
125 buffer3
.reset(); // Old producer releases buffer. Should be a noop.
126 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
127 ASSERT_FALSE(ReserveI420Buffer(size_hi
)) << "Pool should be empty";
129 buffer2
.reset(); // Active producer releases buffer. Should free a buffer.
131 buffer1
= ReserveI420Buffer(size_lo
);
132 ASSERT_TRUE(NULL
!= buffer1
.get());
133 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
135 // First consumer finishes.
136 pool_
->RelinquishConsumerHold(buffer_id3
, 1);
137 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
139 // Second consumer finishes. This should free that buffer.
140 pool_
->RelinquishConsumerHold(buffer_id3
, 1);
141 buffer3
= ReserveI420Buffer(size_lo
);
142 ASSERT_TRUE(NULL
!= buffer3
.get());
143 ASSERT_EQ(buffer_id3
, buffer3
->id()) << "Buffer ID should be reused.";
144 ASSERT_EQ(memory_pointer3
, buffer3
->data());
145 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
147 // Now deliver & consume buffer1, but don't release the buffer.
148 int buffer_id1
= buffer1
->id();
149 ASSERT_EQ(1, buffer_id1
);
150 pool_
->HoldForConsumers(buffer_id1
, 5);
151 pool_
->RelinquishConsumerHold(buffer_id1
, 5);
153 // Even though the consumer is done with the buffer at |buffer_id1|, it cannot
154 // be re-allocated to the producer, because |buffer1| still references it. But
155 // when |buffer1| goes away, we should be able to re-reserve the buffer (and
156 // the ID ought to be the same).
157 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
158 buffer1
.reset(); // Should free the buffer.
159 buffer2
= ReserveI420Buffer(size_lo
);
160 ASSERT_TRUE(NULL
!= buffer2
.get());
161 ASSERT_EQ(buffer_id1
, buffer2
->id());
162 buffer_id2
= buffer_id1
;
163 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
165 // Now try reallocation with different resolutions. We expect reallocation
166 // to occur only when the old buffer is too small.
168 ExpectDroppedId(buffer_id2
);
169 buffer2
= ReserveI420Buffer(size_hi
);
170 ASSERT_TRUE(NULL
!= buffer2
.get());
171 ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420
, size_hi
),
173 ASSERT_EQ(3, buffer2
->id());
174 void* const memory_pointer_hi
= buffer2
->data();
175 buffer2
.reset(); // Frees it.
176 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId
);
177 buffer2
= ReserveI420Buffer(size_lo
);
178 void* const memory_pointer_lo
= buffer2
->data();
179 ASSERT_EQ(memory_pointer_hi
, memory_pointer_lo
)
180 << "Decrease in resolution should not reallocate buffer";
181 ASSERT_TRUE(NULL
!= buffer2
.get());
182 ASSERT_EQ(3, buffer2
->id());
183 ASSERT_LE(media::VideoFrame::AllocationSize(media::VideoFrame::I420
, size_lo
),
185 ASSERT_FALSE(ReserveI420Buffer(size_lo
)) << "Pool should be empty";
187 // Tear down the pool_, writing into the buffers. The buffer should preserve
188 // the lifetime of the underlying memory.
193 memset(buffer2
->data(), 0x22, buffer2
->size());
194 memset(buffer4
->data(), 0x55, buffer4
->size());
198 memset(buffer4
->data(), 0x77, buffer4
->size());
202 } // namespace content