Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Unit test for VideoCaptureBufferPool. | 5 // Unit test for VideoCaptureBufferPool. |
| 6 | 6 |
| 7 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" | 7 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "content/browser/renderer_host/media/video_capture_controller.h" | 12 #include "content/browser/renderer_host/media/video_capture_controller.h" |
| 13 #include "media/base/video_frame.h" | 13 #include "media/base/video_frame.h" |
| 14 #include "media/base/video_util.h" | 14 #include "media/base/video_util.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 16 |
| 17 namespace content { | 17 namespace content { |
| 18 | 18 |
| 19 TEST(VideoCaptureBufferPoolTest, BufferPool) { | 19 class VideoCaptureBufferPoolTest : public testing::Test { |
| 20 const gfx::Size size = gfx::Size(640, 480); | 20 protected: |
| 21 VideoCaptureBufferPoolTest() | |
| 22 : expected_dropped_id_(0), | |
| 23 pool_(new VideoCaptureBufferPool(3)) {} | |
| 24 | |
| 25 void ExpectDroppedId(int expected_dropped_id) { | |
| 26 expected_dropped_id_ = expected_dropped_id; | |
| 27 } | |
| 28 | |
| 29 scoped_refptr<media::VideoFrame> ReserveI420VideoFrame( | |
| 30 const gfx::Size& size) { | |
| 31 int buffer_id_to_drop = ~expected_dropped_id_; | |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
o rly ~ ?
ncarter (slow)
2013/10/16 02:08:40
It's what I intended. What should I use instead? I
Ami GONE FROM CHROMIUM
2013/10/17 20:31:45
I'm not faulting your MAXIMIZATION, which is indee
| |
| 32 scoped_refptr<media::VideoFrame> frame = | |
| 33 pool_->ReserveI420VideoFrame(size, 0, &buffer_id_to_drop); | |
| 34 EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop) | |
| 35 << "Unexpected buffer reallocation result."; | |
| 36 return frame; | |
| 37 } | |
| 38 | |
| 39 int expected_dropped_id_; | |
| 40 scoped_refptr<VideoCaptureBufferPool> pool_; | |
| 41 | |
| 42 private: | |
| 43 DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest); | |
| 44 }; | |
| 45 | |
| 46 TEST_F(VideoCaptureBufferPoolTest, BufferPool) { | |
| 47 const gfx::Size size_lo = gfx::Size(640, 480); | |
| 48 const gfx::Size size_hi = gfx::Size(1024, 768); | |
| 21 scoped_refptr<media::VideoFrame> non_pool_frame = | 49 scoped_refptr<media::VideoFrame> non_pool_frame = |
| 22 media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size, | 50 media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size_lo, |
| 23 gfx::Rect(size), size, base::TimeDelta()); | 51 gfx::Rect(size_lo), size_lo, |
| 24 scoped_refptr<VideoCaptureBufferPool> pool = new VideoCaptureBufferPool( | 52 base::TimeDelta()); |
| 25 media::VideoFrame::AllocationSize(media::VideoFrame::I420, size), 3); | |
| 26 | 53 |
| 27 ASSERT_EQ(460800u, pool->GetMemorySize()); | 54 // Reallocation won't happen for the first part of the test. |
| 28 ASSERT_TRUE(pool->Allocate()); | 55 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId); |
| 29 | 56 |
| 30 scoped_refptr<media::VideoFrame> frame1 = | 57 scoped_refptr<media::VideoFrame> frame1 = ReserveI420VideoFrame(size_lo); |
| 31 pool->ReserveI420VideoFrame(size, 0); | |
| 32 ASSERT_TRUE(NULL != frame1.get()); | 58 ASSERT_TRUE(NULL != frame1.get()); |
| 33 ASSERT_EQ(size, frame1->coded_size()); | 59 ASSERT_EQ(size_lo, frame1->coded_size()); |
| 34 scoped_refptr<media::VideoFrame> frame2 = | 60 scoped_refptr<media::VideoFrame> frame2 = ReserveI420VideoFrame(size_lo); |
| 35 pool->ReserveI420VideoFrame(size, 0); | |
| 36 ASSERT_TRUE(NULL != frame2.get()); | 61 ASSERT_TRUE(NULL != frame2.get()); |
| 37 ASSERT_EQ(size, frame2->coded_size()); | 62 ASSERT_EQ(size_lo, frame2->coded_size()); |
| 38 scoped_refptr<media::VideoFrame> frame3 = | 63 scoped_refptr<media::VideoFrame> frame3 = ReserveI420VideoFrame(size_lo); |
| 39 pool->ReserveI420VideoFrame(size, 0); | |
| 40 ASSERT_TRUE(NULL != frame3.get()); | 64 ASSERT_TRUE(NULL != frame3.get()); |
| 41 | 65 |
| 42 // Touch the memory. | 66 // Touch the memory. |
| 43 media::FillYUV(frame1.get(), 0x11, 0x22, 0x33); | 67 media::FillYUV(frame1.get(), 0x11, 0x22, 0x33); |
| 44 media::FillYUV(frame2.get(), 0x44, 0x55, 0x66); | 68 media::FillYUV(frame2.get(), 0x44, 0x55, 0x66); |
| 45 media::FillYUV(frame3.get(), 0x77, 0x88, 0x99); | 69 media::FillYUV(frame3.get(), 0x77, 0x88, 0x99); |
| 46 | 70 |
| 47 // Fourth frame should fail. | 71 // Fourth frame should fail. |
| 48 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 72 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 49 << "Pool should be empty"; | |
| 50 | 73 |
| 51 // Release 1st frame and retry; this should succeed. | 74 // Release 1st frame and retry; this should succeed. |
| 52 frame1 = NULL; | 75 frame1 = NULL; |
| 53 scoped_refptr<media::VideoFrame> frame4 = | 76 scoped_refptr<media::VideoFrame> frame4 = ReserveI420VideoFrame(size_lo); |
| 54 pool->ReserveI420VideoFrame(size, 0); | |
| 55 ASSERT_TRUE(NULL != frame4.get()); | 77 ASSERT_TRUE(NULL != frame4.get()); |
| 56 | 78 |
| 57 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 79 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 58 << "Pool should be empty"; | 80 ASSERT_FALSE(ReserveI420VideoFrame(size_hi)) << "Pool should be empty"; |
| 59 | 81 |
| 60 // Validate the IDs | 82 // Validate the IDs |
| 61 int buffer_id2 = | 83 int buffer_id2 = |
| 62 pool->RecognizeReservedBuffer(frame2->shared_memory_handle()); | 84 pool_->RecognizeReservedBuffer(frame2->shared_memory_handle()); |
| 63 ASSERT_LE(0, buffer_id2); | 85 ASSERT_EQ(1, buffer_id2); |
| 64 int buffer_id3 = | 86 int buffer_id3 = |
| 65 pool->RecognizeReservedBuffer(frame3->shared_memory_handle()); | 87 pool_->RecognizeReservedBuffer(frame3->shared_memory_handle()); |
| 66 ASSERT_LE(0, buffer_id3); | 88 base::SharedMemoryHandle memory_handle3 = frame3->shared_memory_handle(); |
| 89 ASSERT_EQ(2, buffer_id3); | |
| 67 int buffer_id4 = | 90 int buffer_id4 = |
| 68 pool->RecognizeReservedBuffer(frame4->shared_memory_handle()); | 91 pool_->RecognizeReservedBuffer(frame4->shared_memory_handle()); |
| 69 ASSERT_LE(0, buffer_id4); | 92 ASSERT_EQ(0, buffer_id4); |
| 70 int buffer_id_non_pool = | 93 int buffer_id_non_pool = |
| 71 pool->RecognizeReservedBuffer(non_pool_frame->shared_memory_handle()); | 94 pool_->RecognizeReservedBuffer(non_pool_frame->shared_memory_handle()); |
| 72 ASSERT_GT(0, buffer_id_non_pool); | 95 ASSERT_EQ(VideoCaptureBufferPool::kInvalidId, buffer_id_non_pool); |
| 73 | |
| 74 ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); | |
| 75 | 96 |
| 76 // Deliver a frame. | 97 // Deliver a frame. |
| 77 pool->HoldForConsumers(buffer_id3, 2); | 98 pool_->HoldForConsumers(buffer_id3, 2); |
| 78 | 99 |
| 79 ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); | 100 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 80 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 101 |
| 81 << "Pool should be empty"; | |
| 82 frame3 = NULL; // Old producer releases frame. Should be a noop. | 102 frame3 = NULL; // Old producer releases frame. Should be a noop. |
| 83 ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); | 103 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 84 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 104 ASSERT_FALSE(ReserveI420VideoFrame(size_hi)) << "Pool should be empty"; |
| 85 << "Pool should be empty"; | 105 |
| 86 frame2 = NULL; // Active producer releases frame. Should free a frame. | 106 frame2 = NULL; // Active producer releases frame. Should free a frame. |
| 87 buffer_id2 = 0; | |
| 88 | 107 |
| 89 ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); | 108 frame1 = ReserveI420VideoFrame(size_lo); |
| 90 frame1 = pool->ReserveI420VideoFrame(size, 0); | |
| 91 ASSERT_TRUE(NULL != frame1.get()); | 109 ASSERT_TRUE(NULL != frame1.get()); |
| 92 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 110 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 93 << "Pool should be empty"; | |
| 94 ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); | |
| 95 | 111 |
| 96 // First consumer finishes. | 112 // First consumer finishes. |
| 97 pool->RelinquishConsumerHold(buffer_id3, 1); | 113 pool_->RelinquishConsumerHold(buffer_id3, 1); |
| 98 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 114 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 99 << "Pool should be empty"; | |
| 100 ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); | |
| 101 | 115 |
| 102 // Second consumer finishes. This should free that frame. | 116 // Second consumer finishes. This should free that frame. |
| 103 pool->RelinquishConsumerHold(buffer_id3, 1); | 117 pool_->RelinquishConsumerHold(buffer_id3, 1); |
| 104 ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); | 118 frame3 = ReserveI420VideoFrame(size_lo); |
| 105 frame3 = pool->ReserveI420VideoFrame(size, 0); | |
| 106 ASSERT_TRUE(NULL != frame3.get()); | 119 ASSERT_TRUE(NULL != frame3.get()); |
| 107 ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); | 120 ASSERT_EQ(buffer_id3, |
| 108 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 121 pool_->RecognizeReservedBuffer(frame3->shared_memory_handle())) |
| 109 << "Pool should be empty"; | 122 << "Buffer ID should be reused."; |
| 123 ASSERT_EQ(memory_handle3, frame3->shared_memory_handle()); | |
| 124 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; | |
| 110 | 125 |
| 111 // Now deliver & consume frame1, but don't release the VideoFrame. | 126 // Now deliver & consume frame1, but don't release the VideoFrame. |
| 112 int buffer_id1 = | 127 int buffer_id1 = |
| 113 pool->RecognizeReservedBuffer(frame1->shared_memory_handle()); | 128 pool_->RecognizeReservedBuffer(frame1->shared_memory_handle()); |
| 114 ASSERT_LE(0, buffer_id1); | 129 ASSERT_EQ(1, buffer_id1); |
| 115 pool->HoldForConsumers(buffer_id1, 5); | 130 pool_->HoldForConsumers(buffer_id1, 5); |
| 116 ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); | 131 pool_->RelinquishConsumerHold(buffer_id1, 5); |
| 117 pool->RelinquishConsumerHold(buffer_id1, 5); | |
| 118 ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); | |
| 119 | 132 |
| 120 // Even though the consumer is done with the buffer at |buffer_id1|, it cannot | 133 // Even though the consumer is done with the buffer at |buffer_id1|, it cannot |
| 121 // be re-allocated to the producer, because |frame1| still references it. But | 134 // be re-allocated to the producer, because |frame1| still references it. But |
| 122 // when |frame1| goes away, we should be able to re-reserve the buffer (and | 135 // when |frame1| goes away, we should be able to re-reserve the buffer (and |
| 123 // the ID ought to be the same). | 136 // the ID ought to be the same). |
| 124 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 137 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 125 << "Pool should be empty"; | |
| 126 frame1 = NULL; // Should free the frame. | 138 frame1 = NULL; // Should free the frame. |
| 127 frame2 = pool->ReserveI420VideoFrame(size, 0); | 139 frame2 = ReserveI420VideoFrame(size_lo); |
| 128 ASSERT_TRUE(NULL != frame2.get()); | 140 ASSERT_TRUE(NULL != frame2.get()); |
| 129 ASSERT_EQ(buffer_id1, | 141 ASSERT_EQ(buffer_id1, |
| 130 pool->RecognizeReservedBuffer(frame2->shared_memory_handle())); | 142 pool_->RecognizeReservedBuffer(frame2->shared_memory_handle())); |
| 131 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 143 buffer_id2 = buffer_id1; |
| 132 << "Pool should be empty"; | 144 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; |
| 133 | 145 |
| 134 // For good measure, do one more cycle of free/realloc without delivery, now | 146 // Now try reallocation with different resolutions. We expect reallocation |
| 135 // that this buffer has been through the consumer-hold cycle. | 147 // to occur only when the old buffer is too small. |
| 136 frame2 = NULL; | 148 frame2 = NULL; |
| 137 frame1 = pool->ReserveI420VideoFrame(size, 0); | 149 ExpectDroppedId(buffer_id2); |
| 138 ASSERT_TRUE(NULL != frame1.get()); | 150 frame2 = ReserveI420VideoFrame(size_hi); |
| 139 ASSERT_EQ(buffer_id1, | 151 ASSERT_TRUE(NULL != frame2.get()); |
| 140 pool->RecognizeReservedBuffer(frame1->shared_memory_handle())); | 152 ASSERT_TRUE(frame2->coded_size() == size_hi); |
| 141 ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) | 153 ASSERT_EQ(3, pool_->RecognizeReservedBuffer(frame2->shared_memory_handle())); |
| 142 << "Pool should be empty"; | 154 base::SharedMemoryHandle memory_handle_hi = frame2->shared_memory_handle(); |
| 155 frame2 = NULL; // Frees it. | |
| 156 ExpectDroppedId(VideoCaptureBufferPool::kInvalidId); | |
| 157 frame2 = ReserveI420VideoFrame(size_lo); | |
| 158 base::SharedMemoryHandle memory_handle_lo = frame2->shared_memory_handle(); | |
| 159 ASSERT_EQ(memory_handle_hi, memory_handle_lo) | |
| 160 << "Decrease in resolution should not reallocate buffer"; | |
| 161 ASSERT_TRUE(NULL != frame2.get()); | |
| 162 ASSERT_TRUE(frame2->coded_size() == size_lo); | |
| 163 ASSERT_EQ(3, pool_->RecognizeReservedBuffer(frame2->shared_memory_handle())); | |
| 164 ASSERT_FALSE(ReserveI420VideoFrame(size_lo)) << "Pool should be empty"; | |
| 143 | 165 |
| 144 // Tear down the pool, writing into the frames. The VideoFrame should | 166 // Tear down the pool_, writing into the frames. The VideoFrame should |
| 145 // preserve the lifetime of the underlying memory. | 167 // preserve the lifetime of the underlying memory. |
| 146 frame3 = NULL; | 168 frame3 = NULL; |
| 147 pool = NULL; | 169 pool_ = NULL; |
| 148 | 170 |
| 149 // Touch the memory. | 171 // Touch the memory. |
| 150 media::FillYUV(frame1.get(), 0x11, 0x22, 0x33); | 172 media::FillYUV(frame2.get(), 0x11, 0x22, 0x33); |
| 151 media::FillYUV(frame4.get(), 0x44, 0x55, 0x66); | 173 media::FillYUV(frame4.get(), 0x44, 0x55, 0x66); |
| 152 | 174 |
| 153 frame1 = NULL; | 175 frame2 = NULL; |
| 154 | 176 |
| 155 media::FillYUV(frame4.get(), 0x44, 0x55, 0x66); | 177 media::FillYUV(frame4.get(), 0x44, 0x55, 0x66); |
| 156 frame4 = NULL; | 178 frame4 = NULL; |
| 157 } | 179 } |
| 158 | 180 |
| 159 } // namespace content | 181 } // namespace content |
| OLD | NEW |