12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Unit test for VideoCaptureBufferPool. 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_buffer_pool.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/ref_counted.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/browser/renderer_host/media/video_capture_controller.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/video_frame.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/video_util.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content { 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(VideoCaptureBufferPoolTest, BufferPool) { 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Size size = gfx::Size(640, 480); 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<media::VideoFrame> non_pool_frame = 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size, 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect(size), size, base::TimeDelta()); 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<VideoCaptureBufferPool> pool = 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new VideoCaptureBufferPool(size.GetArea() * 3 / 2, 3); 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(460800u, pool->GetMemorySize()); 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(pool->Allocate()); 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_refptr<media::VideoFrame> frame1 = 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->ReserveI420VideoFrame(size, 0); 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(NULL != frame1.get()); 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(size, frame1->coded_size()); 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_refptr<media::VideoFrame> frame2 = 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->ReserveI420VideoFrame(size, 0); 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(NULL != frame2.get()); 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(size, frame2->coded_size()); 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_refptr<media::VideoFrame> frame3 = 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->ReserveI420VideoFrame(size, 0); 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(NULL != frame3.get()); 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Touch the memory. 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) media::FillYUV(frame1.get(), 0x11, 0x22, 0x33); 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) media::FillYUV(frame2.get(), 0x44, 0x55, 0x66); 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) media::FillYUV(frame3.get(), 0x77, 0x88, 0x99); 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Fourth frame should fail. 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Release 1st frame and retry; this should succeed. 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame1 = NULL; 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_refptr<media::VideoFrame> frame4 = 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->ReserveI420VideoFrame(size, 0); 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(NULL != frame4.get()); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Validate the IDs 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int buffer_id2 = 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->RecognizeReservedBuffer(frame2->shared_memory_handle()); 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_LE(0, buffer_id2); 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int buffer_id3 = 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->RecognizeReservedBuffer(frame3->shared_memory_handle()); 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_LE(0, buffer_id3); 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int buffer_id4 = 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->RecognizeReservedBuffer(frame4->shared_memory_handle()); 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_LE(0, buffer_id4); 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int buffer_id_non_pool = 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->RecognizeReservedBuffer(non_pool_frame->shared_memory_handle()); 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_GT(0, buffer_id_non_pool); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Deliver a frame. 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->HoldForConsumers(buffer_id3, 2); 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame3 = NULL; // Old producer releases frame. Should be a noop. 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame2 = NULL; // Active producer releases frame. Should free a frame. 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer_id2 = 0; 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frame1 = pool->ReserveI420VideoFrame(size, 0); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(NULL != frame1.get()); 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // First consumer finishes. 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pool->RelinquishConsumerHold(buffer_id3, 1); 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Second consumer finishes. This should free that frame. 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pool->RelinquishConsumerHold(buffer_id3, 1); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frame3 = pool->ReserveI420VideoFrame(size, 0); 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ASSERT_TRUE(NULL != frame3.get()); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Now deliver & consume frame1, but don't release the VideoFrame. 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int buffer_id1 = 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->RecognizeReservedBuffer(frame1->shared_memory_handle()); 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_LE(0, buffer_id1); 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->HoldForConsumers(buffer_id1, 5); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(pool->IsAnyBufferHeldForConsumers()); 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pool->RelinquishConsumerHold(buffer_id1, 5); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_FALSE(pool->IsAnyBufferHeldForConsumers()); 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Even though the consumer is done with the buffer at |buffer_id1|, it cannot 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // be re-allocated to the producer, because |frame1| still references it. But 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // when |frame1| goes away, we should be able to re-reserve the buffer (and 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the ID ought to be the same). 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame1 = NULL; // Should free the frame. 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frame2 = pool->ReserveI420VideoFrame(size, 0); 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ASSERT_TRUE(NULL != frame2.get()); 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(buffer_id1, 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->RecognizeReservedBuffer(frame2->shared_memory_handle())); 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // For good measure, do one more cycle of free/realloc without delivery, now 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // that this buffer has been through the consumer-hold cycle. 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame2 = NULL; 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frame1 = pool->ReserveI420VideoFrame(size, 0); 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ASSERT_TRUE(NULL != frame1.get()); 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(buffer_id1, 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pool->RecognizeReservedBuffer(frame1->shared_memory_handle())); 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_EQ(NULL, pool->ReserveI420VideoFrame(size, 0).get()) 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Pool should be empty"; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Tear down the pool, writing into the frames. The VideoFrame should 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // preserve the lifetime of the underlying memory. 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame3 = NULL; 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pool = NULL; 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Touch the memory. 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) media::FillYUV(frame1.get(), 0x11, 0x22, 0x33); 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) media::FillYUV(frame4.get(), 0x44, 0x55, 0x66); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame1 = NULL; 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) media::FillYUV(frame4.get(), 0x44, 0x55, 0x66); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame4 = NULL; 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace content 160