text: // Copyright 2016 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include <stddef.h>
  #include <stdint.h>
  
  #include <cstring>
  
  #include "base/macros.h"
  #include "media/base/video_frame.h"
  #include "media/cdm/api/content_decryption_module.h"
  #include "media/cdm/cdm_helpers.h"
  #include "media/mojo/services/mojo_cdm_allocator.h"
  #include "testing/gtest/include/gtest/gtest.h"
  #include "ui/gfx/geometry/size.h"
  
  namespace media {
  
  class MojoCdmAllocatorTest : public testing::Test {
   public:
    MojoCdmAllocatorTest() {}
    ~MojoCdmAllocatorTest() override {}
  
   protected:
    cdm::Buffer* CreateCdmBuffer(size_t capacity) {
      return allocator_.CreateCdmBuffer(capacity);
    }
  
    std::unique_ptr<VideoFrameImpl> CreateCdmVideoFrame() {
      return allocator_.CreateCdmVideoFrame();
    }
  
    MojoHandle GetHandle(cdm::Buffer* buffer) {
      return allocator_.GetHandleForTesting(buffer);
    }
  
    size_t GetAvailableBufferCount() {
      return allocator_.GetAvailableBufferCountForTesting();
    }
  
   private:
    MojoCdmAllocator allocator_;
    DISALLOW_COPY_AND_ASSIGN(MojoCdmAllocatorTest);
  };
  
  TEST_F(MojoCdmAllocatorTest, CreateCdmBuffer) {
    cdm::Buffer* buffer = CreateCdmBuffer(100);
    EXPECT_GE(buffer->Capacity(), 100u);
    buffer->SetSize(50);
    EXPECT_EQ(50u, buffer->Size());
    buffer->Destroy();
  }
  
  TEST_F(MojoCdmAllocatorTest, ReuseCdmBuffer) {
    const size_t kRandomDataSize = 46;
  
    // Create a small buffer.
    cdm::Buffer* buffer = CreateCdmBuffer(kRandomDataSize);
    MojoHandle handle = GetHandle(buffer);
    buffer->Destroy();
  
    // Now allocate a new buffer of the same size, it should reuse the one
    // just freed.
    cdm::Buffer* new_buffer = CreateCdmBuffer(kRandomDataSize);
    EXPECT_EQ(handle, GetHandle(new_buffer));
    new_buffer->Destroy();
  }
  
  TEST_F(MojoCdmAllocatorTest, MaxFreeBuffers) {
    const size_t kMaxExpectedFreeBuffers = 3;
    size_t buffer_size = 0;
    const size_t kBufferSizeIncrease = 1000;
    std::vector<cdm::Buffer*> buffers;
  
    // Allocate and destroy 10 buffers in increasing size (to avoid buffer reuse).
    // Eventually allocating a new buffer will free the smallest free buffer, so
    // the number of free buffers will be capped at |kMaxExpectedFreeBuffers|.
    for (int i = 0; i < 10; ++i) {
      buffer_size += kBufferSizeIncrease;
      cdm::Buffer* buffer = CreateCdmBuffer(buffer_size);
      buffer->Destroy();
      EXPECT_LE(GetAvailableBufferCount(), kMaxExpectedFreeBuffers);
    }
  }
  
  TEST_F(MojoCdmAllocatorTest, CreateCdmVideoFrame) {
    const size_t kHeight = 16;
    const size_t kWidth = 9;
    const VideoPixelFormat kFormat = PIXEL_FORMAT_I420;
    const gfx::Size kSize(kHeight, kWidth);
    const size_t kBufferSize = VideoFrame::AllocationSize(kFormat, kSize);
  
    // Create a VideoFrameImpl and initialize it.
    std::unique_ptr<VideoFrameImpl> video_frame = CreateCdmVideoFrame();
    video_frame->SetFormat(cdm::kI420);
    video_frame->SetSize(cdm::Size(kHeight, kWidth));
    video_frame->SetStride(
        VideoFrameImpl::kYPlane,
        VideoFrame::RowBytes(VideoFrame::kYPlane, kFormat, kWidth));
    video_frame->SetStride(
        VideoFrameImpl::kUPlane,
        VideoFrame::RowBytes(VideoFrame::kUPlane, kFormat, kWidth));
    video_frame->SetStride(
        VideoFrameImpl::kVPlane,
        VideoFrame::RowBytes(VideoFrame::kVPlane, kFormat, kWidth));
    EXPECT_EQ(nullptr, video_frame->FrameBuffer());
  
    // Now create a buffer to hold the frame and assign it to the VideoFrameImpl.
    cdm::Buffer* buffer = CreateCdmBuffer(kBufferSize);
    EXPECT_EQ(0u, GetAvailableBufferCount());
    buffer->SetSize(kBufferSize);
    video_frame->SetFrameBuffer(buffer);
    EXPECT_NE(nullptr, video_frame->FrameBuffer());
  
    // Transform it into a VideoFrame and make sure the buffer is no longer owned.
    scoped_refptr<VideoFrame> frame = video_frame->TransformToVideoFrame(kSize);
    EXPECT_EQ(nullptr, video_frame->FrameBuffer());
    EXPECT_EQ(0u, GetAvailableBufferCount());
    video_frame.reset();
  
    // Check that the buffer is still in use. It will be freed when |frame|
    // is destroyed.
    EXPECT_EQ(0u, GetAvailableBufferCount());
    frame = nullptr;
  
    // Check that the buffer is now in the free list.
    EXPECT_EQ(1u, GetAvailableBufferCount());
  }
  
  }  // namespace media
  