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