frame_buffer_pool.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright 2017 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. #include "media/filters/frame_buffer_pool.h"
  5. #include "base/bind.h"
  6. #include "base/callback_helpers.h"
  7. #include "base/check_op.h"
  8. #include "base/containers/cxx20_erase.h"
  9. #include "base/location.h"
  10. #include "base/memory/free_deleter.h"
  11. #include "base/process/memory.h"
  12. #include "base/strings/stringprintf.h"
  13. #include "base/task/sequenced_task_runner.h"
  14. #include "base/threading/sequenced_task_runner_handle.h"
  15. #include "base/time/time.h"
  16. #include "base/trace_event/memory_allocator_dump.h"
  17. #include "base/trace_event/memory_dump_manager.h"
  18. #include "base/trace_event/process_memory_dump.h"
  19. namespace media {
  20. struct FrameBufferPool::FrameBuffer {
  21. // Not using std::vector<uint8_t> as resize() calls take a really long time
  22. // for large buffers.
  23. std::unique_ptr<uint8_t, base::FreeDeleter> data;
  24. size_t data_size = 0u;
  25. std::unique_ptr<uint8_t, base::FreeDeleter> alpha_data;
  26. size_t alpha_data_size = 0u;
  27. bool held_by_library = false;
  28. // Needs to be a counter since a frame buffer might be used multiple times.
  29. int held_by_frame = 0;
  30. base::TimeTicks last_use_time;
  31. };
  32. FrameBufferPool::FrameBufferPool()
  33. : tick_clock_(base::DefaultTickClock::GetInstance()) {
  34. DETACH_FROM_SEQUENCE(sequence_checker_);
  35. }
  36. FrameBufferPool::~FrameBufferPool() {
  37. DCHECK(in_shutdown_);
  38. // May be destructed on any thread.
  39. }
  40. uint8_t* FrameBufferPool::GetFrameBuffer(size_t min_size, void** fb_priv) {
  41. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  42. DCHECK(!in_shutdown_);
  43. if (!registered_dump_provider_) {
  44. base::trace_event::MemoryDumpManager::GetInstance()
  45. ->RegisterDumpProviderWithSequencedTaskRunner(
  46. this, "FrameBufferPool", base::SequencedTaskRunnerHandle::Get(),
  47. MemoryDumpProvider::Options());
  48. registered_dump_provider_ = true;
  49. }
  50. // Check if a free frame buffer exists.
  51. auto it = std::find_if(
  52. frame_buffers_.begin(), frame_buffers_.end(),
  53. [](const std::unique_ptr<FrameBuffer>& fb) { return !IsUsed(fb.get()); });
  54. // If not, create one.
  55. if (it == frame_buffers_.end())
  56. it = frame_buffers_.insert(it, std::make_unique<FrameBuffer>());
  57. auto& frame_buffer = *it;
  58. // Resize the frame buffer if necessary.
  59. frame_buffer->held_by_library = true;
  60. if (frame_buffer->data_size < min_size) {
  61. // Free the existing |data| first so that the memory can be reused,
  62. // if possible. Note that the new array is purposely not initialized.
  63. frame_buffer->data.reset();
  64. uint8_t* data = nullptr;
  65. if (force_allocation_error_ ||
  66. !base::UncheckedMalloc(min_size, reinterpret_cast<void**>(&data)) ||
  67. !data) {
  68. frame_buffers_.erase(it);
  69. return nullptr;
  70. }
  71. frame_buffer->data.reset(data);
  72. frame_buffer->data_size = min_size;
  73. }
  74. // Provide the client with a private identifier.
  75. *fb_priv = frame_buffer.get();
  76. return frame_buffer->data.get();
  77. }
  78. void FrameBufferPool::ReleaseFrameBuffer(void* fb_priv) {
  79. DCHECK(fb_priv);
  80. // Note: The library may invoke this method multiple times for the same frame,
  81. // so we can't DCHECK that |held_by_library| is true.
  82. auto* frame_buffer = static_cast<FrameBuffer*>(fb_priv);
  83. frame_buffer->held_by_library = false;
  84. if (!IsUsed(frame_buffer))
  85. frame_buffer->last_use_time = tick_clock_->NowTicks();
  86. }
  87. uint8_t* FrameBufferPool::AllocateAlphaPlaneForFrameBuffer(size_t min_size,
  88. void* fb_priv) {
  89. DCHECK(fb_priv);
  90. auto* frame_buffer = static_cast<FrameBuffer*>(fb_priv);
  91. DCHECK(IsUsed(frame_buffer));
  92. if (frame_buffer->alpha_data_size < min_size) {
  93. // Free the existing |alpha_data| first so that the memory can be reused,
  94. // if possible. Note that the new array is purposely not initialized.
  95. frame_buffer->alpha_data.reset();
  96. uint8_t* data = nullptr;
  97. if (force_allocation_error_ ||
  98. !base::UncheckedMalloc(min_size, reinterpret_cast<void**>(&data)) ||
  99. !data) {
  100. return nullptr;
  101. }
  102. frame_buffer->alpha_data.reset(data);
  103. frame_buffer->alpha_data_size = min_size;
  104. }
  105. return frame_buffer->alpha_data.get();
  106. }
  107. base::OnceClosure FrameBufferPool::CreateFrameCallback(void* fb_priv) {
  108. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  109. auto* frame_buffer = static_cast<FrameBuffer*>(fb_priv);
  110. ++frame_buffer->held_by_frame;
  111. return base::BindOnce(&FrameBufferPool::OnVideoFrameDestroyed, this,
  112. base::SequencedTaskRunnerHandle::Get(), frame_buffer);
  113. }
  114. bool FrameBufferPool::OnMemoryDump(
  115. const base::trace_event::MemoryDumpArgs& args,
  116. base::trace_event::ProcessMemoryDump* pmd) {
  117. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  118. base::trace_event::MemoryAllocatorDump* memory_dump =
  119. pmd->CreateAllocatorDump(
  120. base::StringPrintf("media/frame_buffers/memory_pool/0x%" PRIXPTR,
  121. reinterpret_cast<uintptr_t>(this)));
  122. base::trace_event::MemoryAllocatorDump* used_memory_dump =
  123. pmd->CreateAllocatorDump(
  124. base::StringPrintf("media/frame_buffers/memory_pool/used/0x%" PRIXPTR,
  125. reinterpret_cast<uintptr_t>(this)));
  126. pmd->AddSuballocation(memory_dump->guid(),
  127. base::trace_event::MemoryDumpManager::GetInstance()
  128. ->system_allocator_pool_name());
  129. size_t bytes_used = 0;
  130. size_t bytes_reserved = 0;
  131. for (const auto& frame_buffer : frame_buffers_) {
  132. if (IsUsed(frame_buffer.get()))
  133. bytes_used += frame_buffer->data_size + frame_buffer->alpha_data_size;
  134. bytes_reserved += frame_buffer->data_size + frame_buffer->alpha_data_size;
  135. }
  136. memory_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
  137. base::trace_event::MemoryAllocatorDump::kUnitsBytes,
  138. bytes_reserved);
  139. used_memory_dump->AddScalar(
  140. base::trace_event::MemoryAllocatorDump::kNameSize,
  141. base::trace_event::MemoryAllocatorDump::kUnitsBytes, bytes_used);
  142. return true;
  143. }
  144. void FrameBufferPool::Shutdown() {
  145. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  146. in_shutdown_ = true;
  147. if (registered_dump_provider_) {
  148. base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
  149. this);
  150. }
  151. // Clear any refs held by the library which isn't good about cleaning up after
  152. // itself. This is safe since the library has already been shutdown by this
  153. // point.
  154. for (const auto& frame_buffer : frame_buffers_)
  155. frame_buffer->held_by_library = false;
  156. EraseUnusedResources();
  157. }
  158. // static
  159. bool FrameBufferPool::IsUsed(const FrameBuffer* buf) {
  160. return buf->held_by_library || buf->held_by_frame > 0;
  161. }
  162. void FrameBufferPool::EraseUnusedResources() {
  163. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  164. base::EraseIf(frame_buffers_, [](const std::unique_ptr<FrameBuffer>& buf) {
  165. return !IsUsed(buf.get());
  166. });
  167. }
  168. void FrameBufferPool::OnVideoFrameDestroyed(
  169. scoped_refptr<base::SequencedTaskRunner> task_runner,
  170. FrameBuffer* frame_buffer) {
  171. if (!task_runner->RunsTasksInCurrentSequence()) {
  172. task_runner->PostTask(
  173. FROM_HERE, base::BindOnce(&FrameBufferPool::OnVideoFrameDestroyed, this,
  174. task_runner, frame_buffer));
  175. return;
  176. }
  177. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  178. DCHECK_GT(frame_buffer->held_by_frame, 0);
  179. --frame_buffer->held_by_frame;
  180. if (in_shutdown_) {
  181. // If we're in shutdown we can be sure that the library has been destroyed.
  182. EraseUnusedResources();
  183. return;
  184. }
  185. const base::TimeTicks now = tick_clock_->NowTicks();
  186. if (!IsUsed(frame_buffer))
  187. frame_buffer->last_use_time = now;
  188. base::EraseIf(frame_buffers_, [now](const std::unique_ptr<FrameBuffer>& buf) {
  189. return !IsUsed(buf.get()) &&
  190. now - buf->last_use_time > base::Seconds(kStaleFrameLimitSecs);
  191. });
  192. }
  193. } // namespace media