Home | History | Annotate | Download | only in media
      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.
      4 
      5 // Unit test for VideoCaptureBufferPool.
      6 
      7 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
      8 
      9 #include "base/bind.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"
     16 
     17 namespace content {
     18 
     19 class VideoCaptureBufferPoolTest : public testing::Test {
     20  protected:
     21   class Buffer {
     22    public:
     23     Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
     24            int id,
     25            void* data,
     26            size_t size)
     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_; }
     32 
     33    private:
     34     const scoped_refptr<VideoCaptureBufferPool> pool_;
     35     const int id_;
     36     void* const data_;
     37     const size_t size_;
     38   };
     39   VideoCaptureBufferPoolTest()
     40       : expected_dropped_id_(0),
     41         pool_(new VideoCaptureBufferPool(3)) {}
     42 
     43   void ExpectDroppedId(int expected_dropped_id) {
     44     expected_dropped_id_ = expected_dropped_id;
     45   }
     46 
     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>();
     56 
     57     void* memory;
     58     size_t size;
     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));
     62   }
     63 
     64   int expected_dropped_id_;
     65   scoped_refptr<VideoCaptureBufferPool> pool_;
     66 
     67  private:
     68   DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest);
     69 };
     70 
     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,
     77                                      base::TimeDelta());
     78 
     79   // Reallocation won't happen for the first part of the test.
     80   ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
     81 
     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),
     85             buffer1->size());
     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),
     89             buffer2->size());
     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),
     93             buffer3->size());
     94 
     95   // Touch the memory.
     96   memset(buffer1->data(), 0x11, buffer1->size());
     97   memset(buffer2->data(), 0x44, buffer2->size());
     98   memset(buffer3->data(), 0x77, buffer3->size());
     99 
    100   // Fourth buffer should fail.
    101   ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
    102 
    103   // Release 1st buffer and retry; this should succeed.
    104   buffer1.reset();
    105   scoped_ptr<Buffer> buffer4 = ReserveI420Buffer(size_lo);
    106   ASSERT_TRUE(NULL != buffer4.get());
    107 
    108   ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
    109   ASSERT_FALSE(ReserveI420Buffer(size_hi)) << "Pool should be empty";
    110 
    111   // Validate the IDs
    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);
    119 
    120   // Deliver a buffer.
    121   pool_->HoldForConsumers(buffer_id3, 2);
    122 
    123   ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
    124 
    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";
    128 
    129   buffer2.reset();  // Active producer releases buffer. Should free a buffer.
    130 
    131   buffer1 = ReserveI420Buffer(size_lo);
    132   ASSERT_TRUE(NULL != buffer1.get());
    133   ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
    134 
    135   // First consumer finishes.
    136   pool_->RelinquishConsumerHold(buffer_id3, 1);
    137   ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
    138 
    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";
    146 
    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);
    152 
    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";
    164 
    165   // Now try reallocation with different resolutions. We expect reallocation
    166   // to occur only when the old buffer is too small.
    167   buffer2.reset();
    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),
    172             buffer2->size());
    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),
    184             buffer2->size());
    185   ASSERT_FALSE(ReserveI420Buffer(size_lo)) << "Pool should be empty";
    186 
    187   // Tear down the pool_, writing into the buffers. The buffer should preserve
    188   // the lifetime of the underlying memory.
    189   buffer3.reset();
    190   pool_ = NULL;
    191 
    192   // Touch the memory.
    193   memset(buffer2->data(), 0x22, buffer2->size());
    194   memset(buffer4->data(), 0x55, buffer4->size());
    195 
    196   buffer2.reset();
    197 
    198   memset(buffer4->data(), 0x77, buffer4->size());
    199   buffer4.reset();
    200 }
    201 
    202 } // namespace content
    203