123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- // Copyright 2017 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 "media/filters/frame_buffer_pool.h"
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/check_op.h"
- #include "base/containers/cxx20_erase.h"
- #include "base/location.h"
- #include "base/memory/free_deleter.h"
- #include "base/process/memory.h"
- #include "base/strings/stringprintf.h"
- #include "base/task/sequenced_task_runner.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "base/time/time.h"
- #include "base/trace_event/memory_allocator_dump.h"
- #include "base/trace_event/memory_dump_manager.h"
- #include "base/trace_event/process_memory_dump.h"
- namespace media {
- struct FrameBufferPool::FrameBuffer {
- // Not using std::vector<uint8_t> as resize() calls take a really long time
- // for large buffers.
- std::unique_ptr<uint8_t, base::FreeDeleter> data;
- size_t data_size = 0u;
- std::unique_ptr<uint8_t, base::FreeDeleter> alpha_data;
- size_t alpha_data_size = 0u;
- bool held_by_library = false;
- // Needs to be a counter since a frame buffer might be used multiple times.
- int held_by_frame = 0;
- base::TimeTicks last_use_time;
- };
- FrameBufferPool::FrameBufferPool()
- : tick_clock_(base::DefaultTickClock::GetInstance()) {
- DETACH_FROM_SEQUENCE(sequence_checker_);
- }
- FrameBufferPool::~FrameBufferPool() {
- DCHECK(in_shutdown_);
- // May be destructed on any thread.
- }
- uint8_t* FrameBufferPool::GetFrameBuffer(size_t min_size, void** fb_priv) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!in_shutdown_);
- if (!registered_dump_provider_) {
- base::trace_event::MemoryDumpManager::GetInstance()
- ->RegisterDumpProviderWithSequencedTaskRunner(
- this, "FrameBufferPool", base::SequencedTaskRunnerHandle::Get(),
- MemoryDumpProvider::Options());
- registered_dump_provider_ = true;
- }
- // Check if a free frame buffer exists.
- auto it = std::find_if(
- frame_buffers_.begin(), frame_buffers_.end(),
- [](const std::unique_ptr<FrameBuffer>& fb) { return !IsUsed(fb.get()); });
- // If not, create one.
- if (it == frame_buffers_.end())
- it = frame_buffers_.insert(it, std::make_unique<FrameBuffer>());
- auto& frame_buffer = *it;
- // Resize the frame buffer if necessary.
- frame_buffer->held_by_library = true;
- if (frame_buffer->data_size < min_size) {
- // Free the existing |data| first so that the memory can be reused,
- // if possible. Note that the new array is purposely not initialized.
- frame_buffer->data.reset();
- uint8_t* data = nullptr;
- if (force_allocation_error_ ||
- !base::UncheckedMalloc(min_size, reinterpret_cast<void**>(&data)) ||
- !data) {
- frame_buffers_.erase(it);
- return nullptr;
- }
- frame_buffer->data.reset(data);
- frame_buffer->data_size = min_size;
- }
- // Provide the client with a private identifier.
- *fb_priv = frame_buffer.get();
- return frame_buffer->data.get();
- }
- void FrameBufferPool::ReleaseFrameBuffer(void* fb_priv) {
- DCHECK(fb_priv);
- // Note: The library may invoke this method multiple times for the same frame,
- // so we can't DCHECK that |held_by_library| is true.
- auto* frame_buffer = static_cast<FrameBuffer*>(fb_priv);
- frame_buffer->held_by_library = false;
- if (!IsUsed(frame_buffer))
- frame_buffer->last_use_time = tick_clock_->NowTicks();
- }
- uint8_t* FrameBufferPool::AllocateAlphaPlaneForFrameBuffer(size_t min_size,
- void* fb_priv) {
- DCHECK(fb_priv);
- auto* frame_buffer = static_cast<FrameBuffer*>(fb_priv);
- DCHECK(IsUsed(frame_buffer));
- if (frame_buffer->alpha_data_size < min_size) {
- // Free the existing |alpha_data| first so that the memory can be reused,
- // if possible. Note that the new array is purposely not initialized.
- frame_buffer->alpha_data.reset();
- uint8_t* data = nullptr;
- if (force_allocation_error_ ||
- !base::UncheckedMalloc(min_size, reinterpret_cast<void**>(&data)) ||
- !data) {
- return nullptr;
- }
- frame_buffer->alpha_data.reset(data);
- frame_buffer->alpha_data_size = min_size;
- }
- return frame_buffer->alpha_data.get();
- }
- base::OnceClosure FrameBufferPool::CreateFrameCallback(void* fb_priv) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- auto* frame_buffer = static_cast<FrameBuffer*>(fb_priv);
- ++frame_buffer->held_by_frame;
- return base::BindOnce(&FrameBufferPool::OnVideoFrameDestroyed, this,
- base::SequencedTaskRunnerHandle::Get(), frame_buffer);
- }
- bool FrameBufferPool::OnMemoryDump(
- const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- base::trace_event::MemoryAllocatorDump* memory_dump =
- pmd->CreateAllocatorDump(
- base::StringPrintf("media/frame_buffers/memory_pool/0x%" PRIXPTR,
- reinterpret_cast<uintptr_t>(this)));
- base::trace_event::MemoryAllocatorDump* used_memory_dump =
- pmd->CreateAllocatorDump(
- base::StringPrintf("media/frame_buffers/memory_pool/used/0x%" PRIXPTR,
- reinterpret_cast<uintptr_t>(this)));
- pmd->AddSuballocation(memory_dump->guid(),
- base::trace_event::MemoryDumpManager::GetInstance()
- ->system_allocator_pool_name());
- size_t bytes_used = 0;
- size_t bytes_reserved = 0;
- for (const auto& frame_buffer : frame_buffers_) {
- if (IsUsed(frame_buffer.get()))
- bytes_used += frame_buffer->data_size + frame_buffer->alpha_data_size;
- bytes_reserved += frame_buffer->data_size + frame_buffer->alpha_data_size;
- }
- memory_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes,
- bytes_reserved);
- used_memory_dump->AddScalar(
- base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes, bytes_used);
- return true;
- }
- void FrameBufferPool::Shutdown() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- in_shutdown_ = true;
- if (registered_dump_provider_) {
- base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
- this);
- }
- // Clear any refs held by the library which isn't good about cleaning up after
- // itself. This is safe since the library has already been shutdown by this
- // point.
- for (const auto& frame_buffer : frame_buffers_)
- frame_buffer->held_by_library = false;
- EraseUnusedResources();
- }
- // static
- bool FrameBufferPool::IsUsed(const FrameBuffer* buf) {
- return buf->held_by_library || buf->held_by_frame > 0;
- }
- void FrameBufferPool::EraseUnusedResources() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- base::EraseIf(frame_buffers_, [](const std::unique_ptr<FrameBuffer>& buf) {
- return !IsUsed(buf.get());
- });
- }
- void FrameBufferPool::OnVideoFrameDestroyed(
- scoped_refptr<base::SequencedTaskRunner> task_runner,
- FrameBuffer* frame_buffer) {
- if (!task_runner->RunsTasksInCurrentSequence()) {
- task_runner->PostTask(
- FROM_HERE, base::BindOnce(&FrameBufferPool::OnVideoFrameDestroyed, this,
- task_runner, frame_buffer));
- return;
- }
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_GT(frame_buffer->held_by_frame, 0);
- --frame_buffer->held_by_frame;
- if (in_shutdown_) {
- // If we're in shutdown we can be sure that the library has been destroyed.
- EraseUnusedResources();
- return;
- }
- const base::TimeTicks now = tick_clock_->NowTicks();
- if (!IsUsed(frame_buffer))
- frame_buffer->last_use_time = now;
- base::EraseIf(frame_buffers_, [now](const std::unique_ptr<FrameBuffer>& buf) {
- return !IsUsed(buf.get()) &&
- now - buf->last_use_time > base::Seconds(kStaleFrameLimitSecs);
- });
- }
- } // namespace media
|