Add helper classes to for managing shared buffers.
First of a series of patches for Motown.
FifoAllocator - does the bookkeeping to implement heap semantics on an
imaginary buffer assuming normal streaming behavior (first allocated,
first released).
MappedSharedBuffer - owns a shared buffer, maps and unmaps it and does
offset/pointer conversions.
SharedMediaBufferAllocator - derived from MappedSharedBuffer, adds
heap semantics using FifoAllocator and thread safety.
BUG=none
R=johngro@google.com
Review URL: https://codereview.chromium.org/1460693004 .
diff --git a/.gitignore b/.gitignore
index d1bb5d5..e24c222 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,7 +39,7 @@
/third_party/colorama/src/
/third_party/dart-sdk/
/third_party/dejavu-fonts-ttf-2.34/ttf/*.ttf
-/third_party/ffmpeg
+/third_party/ffmpeg/
/third_party/freetype-android/src
/third_party/go/
/third_party/icu/
diff --git a/mojo/services/media/common/cpp/BUILD.gn b/mojo/services/media/common/cpp/BUILD.gn
index 98697a8..627a726 100644
--- a/mojo/services/media/common/cpp/BUILD.gn
+++ b/mojo/services/media/common/cpp/BUILD.gn
@@ -10,9 +10,15 @@
sources = [
"circular_buffer_media_pipe_adapter.cc",
"circular_buffer_media_pipe_adapter.h",
+ "fifo_allocator.cc",
+ "fifo_allocator.h",
"linear_transform.cc",
"linear_transform.h",
"local_time.h",
+ "mapped_shared_buffer.cc",
+ "mapped_shared_buffer.h",
+ "shared_media_buffer_allocator.cc",
+ "shared_media_buffer_allocator.h",
]
if (is_posix) {
diff --git a/mojo/services/media/common/cpp/fifo_allocator.cc b/mojo/services/media/common/cpp/fifo_allocator.cc
new file mode 100644
index 0000000..0bbb69d
--- /dev/null
+++ b/mojo/services/media/common/cpp/fifo_allocator.cc
@@ -0,0 +1,222 @@
+// Copyright 2015 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 "mojo/public/cpp/environment/logging.h"
+#include "mojo/services/media/common/cpp/fifo_allocator.h"
+
+namespace mojo {
+namespace media {
+
+FifoAllocator::FifoAllocator(uint64_t size) : front_(nullptr), free_(nullptr) {
+ // front_ and free_ need to be set to nullptr before calling reset.
+ Reset(size);
+}
+
+FifoAllocator::~FifoAllocator() {
+ DeleteFrontToBack(front_);
+ DeleteFrontToBack(free_);
+}
+
+void FifoAllocator::Reset(uint64_t size) {
+ MOJO_DCHECK(size < kNullOffset);
+ DeleteFrontToBack(front_);
+ DeleteFrontToBack(free_);
+ size_ = size;
+ free_ = nullptr;
+ front_ = back_ = active_ = get_free(false, size, 0);
+ active_->prev = nullptr;
+ active_->next = nullptr;
+}
+
+uint64_t FifoAllocator::AllocateRegion(uint64_t size) {
+ MOJO_DCHECK(size != 0);
+
+ if (active_->size < size) {
+ // The active region is too small. Look for one that's large enough.
+ if (!AdvanceActive(size)) {
+ // No unallocated regions are large enough. Can't do the allocation.
+ return kNullOffset;
+ }
+ }
+
+ if (active_->size == size) {
+ // The active region is exactly the right size. Use it for the allocation.
+ uint64_t result = active_->offset;
+ active_->allocated = true;
+ if (active_ == back_ && !front_->allocated) {
+ // active_ was the back region and the front region isn't allocated. Make
+ // the front region the new active region.
+ active_ = front_;
+ } else {
+ // The region after active_ is allocated, so make a zero-sized
+ // placeholder.
+ MakeActivePlaceholder();
+ }
+ return result;
+ }
+
+ // The active region can accommodate this allocation with room left over.
+ // Create a new region (allocated) of the requested size at the front of the
+ // active region, and adjust the active region to reflect the deficit.
+ MOJO_DCHECK(active_->size > size);
+ Region *allocated = get_free(true, size, active_->offset);
+ active_->size -= size;
+ active_->offset += size;
+ insert_before(allocated, active_);
+ return allocated->offset;
+}
+
+void FifoAllocator::ReleaseRegion(uint64_t size, uint64_t offset) {
+ // Start at active_->next. That's usually the region we're looking for.
+ bool released =
+ Release(size, offset, active_->next, nullptr) ||
+ Release(size, offset, front_, active_);
+ MOJO_DCHECK(released);
+}
+
+bool FifoAllocator::Release(
+ uint64_t size,
+ uint64_t offset,
+ Region* begin,
+ Region* end) {
+ MOJO_DCHECK(begin != nullptr || end == nullptr);
+ for (Region* region = begin; region != end; region = region->next) {
+ if (region->offset == offset) {
+ MOJO_DCHECK(region->allocated);
+ MOJO_DCHECK(region->size == size);
+ region->allocated = false;
+
+ Region *prev = region->prev;
+ if (prev != nullptr && !prev->allocated) {
+ // Coalesce wtih the previous region.
+ prev->size += region->size;
+ remove(region);
+ put_free(region);
+ region = prev;
+ }
+
+ Region *next = region->next;
+ if (next != nullptr && !next->allocated) {
+ // Coalesce wtih the next region.
+ next->offset = region->offset;
+ next->size += region->size;
+ if (active_ == region) {
+ // This can happen if we coalesced the previous region.
+ active_ = next;
+ }
+ remove(region);
+ put_free(region);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool FifoAllocator::AdvanceActive(uint64_t size) {
+ MOJO_DCHECK(size != 0);
+ return
+ AdvanceActive(size, active_->next, nullptr) ||
+ AdvanceActive(size, front_, active_);
+}
+
+bool FifoAllocator::AdvanceActive(uint64_t size, Region* begin, Region* end) {
+ for (Region* region = begin; region != end; region = region->next) {
+ if (!region->allocated && region->size >= size) {
+ if (active_->size == 0) {
+ // The old active region is zero-sized. Get rid of it.
+ MOJO_DCHECK(!active_->allocated);
+ remove(active_);
+ put_free(active_);
+ }
+ active_ = region;
+ return true;
+ }
+ }
+ return false;
+}
+
+void FifoAllocator::MakeActivePlaceholder() {
+ // If the old active region was at the back of the list, we'll be inserting
+ // at the front, so make the offset zero. We insert at the front, because it's
+ // a bit more efficient and because we don't need to implement insert_after.
+ Region *new_active = get_free(
+ false,
+ 0,
+ active_ == back_ ? 0 : active_->offset + active_->size);
+
+ MOJO_DCHECK((active_ == back_) == (active_->next == nullptr));
+ insert_before(new_active, active_ == back_ ? front_ : active_->next);
+ active_ = new_active;
+}
+
+void FifoAllocator::remove(Region* region) {
+ MOJO_DCHECK(region);
+
+ if (front_ == region) {
+ MOJO_DCHECK(region->prev == nullptr);
+ front_ = region->next;
+ } else {
+ MOJO_DCHECK(region->prev);
+ MOJO_DCHECK(region->prev->next ==region);
+ region->prev->next = region->next;
+ }
+
+ if (back_ == region) {
+ MOJO_DCHECK(region->next == nullptr);
+ back_ = region->prev;
+ } else {
+ MOJO_DCHECK(region->next);
+ MOJO_DCHECK(region->next->prev == region);
+ region->next->prev = region->prev;
+ }
+}
+
+void FifoAllocator::insert_before(Region* region, Region* before_this) {
+ MOJO_DCHECK(region);
+ MOJO_DCHECK(before_this);
+
+ region->prev = before_this->prev;
+ before_this->prev = region;
+ region->next = before_this;
+ if (front_ == before_this) {
+ MOJO_DCHECK(region->prev == nullptr);
+ front_ = region;
+ } else {
+ MOJO_DCHECK(region->prev);
+ region->prev->next = region;
+ }
+}
+
+FifoAllocator::Region* FifoAllocator::get_free(
+ bool allocated, uint64_t size, uint64_t offset) {
+ MOJO_DCHECK(size <= size_);
+ MOJO_DCHECK(offset <= size_ - size);
+
+ Region *result = free_;
+ if (result == nullptr) {
+ result = new Region();
+ } else {
+ free_ = free_->next;
+ }
+
+ result->allocated = allocated;
+ result->size = size;
+ result->offset = offset;
+
+ return result;
+}
+
+void FifoAllocator::DeleteFrontToBack(Region* region) {
+ while (region != nullptr) {
+ Region *to_delete = region;
+ region = region->next;
+ delete to_delete;
+ }
+}
+
+} // namespace media
+} // namespace mojo
diff --git a/mojo/services/media/common/cpp/fifo_allocator.h b/mojo/services/media/common/cpp/fifo_allocator.h
new file mode 100644
index 0000000..538223e
--- /dev/null
+++ b/mojo/services/media/common/cpp/fifo_allocator.h
@@ -0,0 +1,147 @@
+// Copyright 2015 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.
+
+#ifndef MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_
+
+#include <cstdint>
+#include <limits>
+
+namespace mojo {
+namespace media {
+
+// FifoAllocator implements heap semantics on a single contiguous buffer using
+// a strategy that is especially suited to streaming. Allocations can vary in
+// size, but the expectation is that regions will be released in roughly the
+// order they were allocated (hence 'Fifo'). It's important that FifoAllocator
+// be used in this way. FifoAllocator can deal with regions that don't get
+// released in the order they were allocated, but they can potentially fragment
+// the buffer and impact performance.
+//
+// FifoAllocator doesn't actually deal with any particular region of memory. It
+// simply does the bookkeeping regarding how a buffer of a given size is
+// allocated into regions.
+//
+// DESIGN:
+//
+// FifoAllocator maintains an ordered list of regions that partition the buffer.
+// Some regions are allocated and some are free. Free regions are always
+// coalesced, so there are no two adjacent free regions. Allocated regions are
+// not coalesced. There is always at least one free region.
+//
+// One free region is distinguished as the 'active' region. New allocations are
+// taken from the front of the active region. If the active region is too small
+// to accommodate a requested allocation, FifoAllocator walks the list looking
+// for an unallocated region that's large enough. The old active region becomes
+// an unused scrap that is recovered when the active region catches up to it
+// again. In some cases, the active region has a length of zero.
+//
+// The allocation strategy that emerges from all this is well-suited to many
+// streaming scenarios in which packets vary in size. If packets are of
+// consistent size, this strategy will still work, but is overkill given that
+// a fixed set of regions can be preallocated from the buffer.
+//
+// An internal region structure is employed to represent the list of regions.
+// FifoAllocator keeps unused region structures in a lookaside and never deletes
+// them until the FifoAllocator is deleted. This could cause a large number of
+// region structures to sit unused if the number of regions ever gets large.
+// This is generally not an issue for the streaming scenarios for which the
+// class is intended.
+//
+// Deallocations (releases) employ a sequential search for a matching
+// region. The search is done starting immediately after the active region, so
+// it typically finds the desired region immediately. If the number of regions
+// is very large and deallocation is frequently done out of order, the
+// sequential searches may be a performance issue.
+class FifoAllocator {
+ public:
+ // Returned by AllocatedRegion when the requested allocation cannot be
+ // performed.
+ static const uint64_t kNullOffset = std::numeric_limits<uint64_t>::max();
+
+ FifoAllocator(uint64_t size);
+
+ ~FifoAllocator();
+
+ // Returns the size of the entire buffer as determined by the call to the
+ // constructor or the most recent call to Reset.
+ uint64_t size() const {
+ return size_;
+ }
+
+ // Resets the buffer manager to its initial state (no regions allocated)
+ // with a new buffer size. Also deletes all the regions in the lookaside.
+ void Reset(uint64_t size);
+
+ // Allocates a region and returns its offset or kNullOffset if the allocation
+ // could not be performed.
+ uint64_t AllocateRegion(uint64_t size);
+
+ // Releases a previously-allocated region.
+ void ReleaseRegion(uint64_t size, uint64_t offset);
+
+ private:
+ // List element to track allocated and free regions.
+ struct Region {
+ bool allocated;
+ uint64_t size;
+ uint64_t offset;
+
+ // Intrusive list pointers.
+ Region* prev;
+ Region* next;
+ };
+
+ // Releases the specified region if it's found between begin (inclusive) and
+ // end (exclusive).
+ bool Release(uint64_t size, uint64_t offset, Region* begin, Region* end);
+
+ // Advances the active region to one that's at least the specified size.
+ // Returns false if none could be found.
+ bool AdvanceActive(uint64_t size);
+
+ // Does the above for the interval between begin (inclusive) and end
+ // (exclusive).
+ bool AdvanceActive(uint64_t size, Region* begin, Region* end);
+
+ // Inserts a zero-sized region after active_ and makes that the active region.
+ void MakeActivePlaceholder();
+
+ // Deletes a list of regions by following their next pointers.
+ void DeleteFrontToBack(Region* region);
+
+ // Removes a region from the list.
+ void remove(Region* region);
+
+ // Inserts a region into the list before the specified region.
+ void insert_before(Region* region, Region* before_this);
+
+ // gets a free region structure, checking the lookaside first.
+ Region* get_free(bool allocated, uint64_t size, uint64_t offset);
+
+ // Saves a unused region structure to the lookaside.
+ void put_free(Region* region) {
+ region->next = free_;
+ free_ = region;
+ }
+
+ // Total size of the buffer to be managed. The sum of the sizes of all the
+ // regions in the list should equal size_.
+ uint64_t size_;
+
+ // Doubly-linked intrusive list of current regions in offset order.
+ Region* front_;
+ Region* back_;
+
+ // Lookaside for free region objects.
+ Region* free_;
+
+ // Unallocated region from which allocations are currently being made.
+ Region* active_;
+};
+
+} // namespace media
+} // namespace mojo
+
+#endif // MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_
diff --git a/mojo/services/media/common/cpp/mapped_shared_buffer.cc b/mojo/services/media/common/cpp/mapped_shared_buffer.cc
new file mode 100644
index 0000000..5d0cb4b
--- /dev/null
+++ b/mojo/services/media/common/cpp/mapped_shared_buffer.cc
@@ -0,0 +1,104 @@
+// Copyright 2015 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 "mojo/public/cpp/environment/logging.h"
+#include "mojo/services/media/common/cpp/mapped_shared_buffer.h"
+
+namespace mojo {
+namespace media {
+
+MappedSharedBuffer::MappedSharedBuffer() {}
+
+MappedSharedBuffer::~MappedSharedBuffer() {}
+
+void MappedSharedBuffer::InitNew(uint64_t size) {
+ MOJO_DCHECK(size > 0);
+
+ buffer_.reset(new SharedBuffer(size));
+ handle_.reset();
+
+ InitInternal(buffer_->handle, size);
+}
+
+void MappedSharedBuffer::InitFromHandle(
+ ScopedSharedBufferHandle handle,
+ uint64_t size) {
+ MOJO_DCHECK(handle.is_valid());
+ MOJO_DCHECK(size > 0);
+
+ buffer_.reset();
+ handle_ = handle.Pass();
+
+ InitInternal(handle_, size);
+}
+
+void MappedSharedBuffer::InitInternal(
+ ScopedSharedBufferHandle& handle,
+ uint64_t size) {
+ MOJO_DCHECK(handle.is_valid());
+ MOJO_DCHECK(size > 0);
+
+ size_ = size;
+ buffer_ptr_.reset();
+
+ void* ptr;
+ auto result = MapBuffer(
+ handle.get(),
+ 0, // offset
+ size,
+ &ptr,
+ MOJO_MAP_BUFFER_FLAG_NONE);
+ MOJO_DCHECK(result == MOJO_RESULT_OK);
+ MOJO_DCHECK(ptr);
+
+ buffer_ptr_.reset(reinterpret_cast<uint8_t*>(ptr));
+
+ OnInit();
+}
+
+bool MappedSharedBuffer::initialized() const {
+ return buffer_ptr_ != nullptr;
+}
+
+uint64_t MappedSharedBuffer::size() const {
+ return size_;
+}
+
+ScopedSharedBufferHandle MappedSharedBuffer::GetDuplicateHandle() const {
+ MOJO_DCHECK(initialized());
+ ScopedSharedBufferHandle handle;
+ if (buffer_) {
+ DuplicateBuffer(buffer_->handle.get(), nullptr, &handle);
+ } else {
+ MOJO_DCHECK(handle_.is_valid());
+ DuplicateBuffer(handle_.get(), nullptr, &handle);
+ }
+ return handle.Pass();
+}
+
+void* MappedSharedBuffer::PtrFromOffset(uint64_t offset) const {
+ MOJO_DCHECK(buffer_ptr_);
+
+ if (offset == FifoAllocator::kNullOffset) {
+ return nullptr;
+ }
+
+ MOJO_DCHECK(offset < size_);
+ return buffer_ptr_.get() + offset;
+}
+
+uint64_t MappedSharedBuffer::OffsetFromPtr(void *ptr) const {
+ MOJO_DCHECK(buffer_ptr_);
+ if (ptr == nullptr) {
+ return FifoAllocator::kNullOffset;
+ }
+ uint64_t offset = reinterpret_cast<uint8_t*>(ptr) - buffer_ptr_.get();
+ MOJO_DCHECK(offset < size_);
+ return offset;
+}
+
+void MappedSharedBuffer::OnInit() {}
+
+} // namespace media
+} // namespace mojo
diff --git a/mojo/services/media/common/cpp/mapped_shared_buffer.h b/mojo/services/media/common/cpp/mapped_shared_buffer.h
new file mode 100644
index 0000000..5fd7e8a
--- /dev/null
+++ b/mojo/services/media/common/cpp/mapped_shared_buffer.h
@@ -0,0 +1,81 @@
+// Copyright 2015 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.
+
+#ifndef MOJO_SERVICES_MEDIA_COMMON_CPP_MAPPED_SHARED_BUFFER_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_MAPPED_SHARED_BUFFER_H_
+
+#include <memory>
+
+#include "mojo/public/cpp/system/buffer.h"
+#include "mojo/services/media/common/cpp/fifo_allocator.h"
+
+namespace mojo {
+namespace media {
+
+// MappedSharedBuffer simplifies the use of shared buffers by taking care of
+// mapping/unmapping and by providing offset/pointer translation. It can be
+// used when the caller wants to allocate its own buffer (InitNew) and when
+// the caller needs to use a buffer supplied by another party (InitFromHandle).
+// It can be used by itself when regions of the buffer are allocated by another
+// party. If the caller needs to allocate regions, SharedMediaBufferAllocator,
+// which is derived from MappedSharedBuffer, provides allocation semantics
+// using FifoAllocator.
+class MappedSharedBuffer {
+ public:
+ MappedSharedBuffer();
+
+ virtual ~MappedSharedBuffer();
+
+ // Initializes by creating a new shared buffer of the indicated size.
+ void InitNew(uint64_t size);
+
+ // Initializes from a handle to an existing shared buffer.
+ void InitFromHandle(ScopedSharedBufferHandle handle, uint64_t size);
+
+ // Indicates whether the buffer is initialized.
+ bool initialized() const;
+
+ // Gets the size of the buffer.
+ uint64_t size() const;
+
+ // Gets a duplicate handle for the shared buffer.
+ ScopedSharedBufferHandle GetDuplicateHandle() const;
+
+ // Translates an offset into a pointer.
+ void* PtrFromOffset(uint64_t offset) const;
+
+ // Translates a pointer into an offset.
+ uint64_t OffsetFromPtr(void *payload_ptr) const;
+
+ protected:
+ void InitInternal(ScopedSharedBufferHandle& handle, uint64_t size);
+
+ // Does nothing. Called when initialization is complete. Subclasses may
+ // override.
+ virtual void OnInit();
+
+ private:
+ struct MappedBufferDeleter {
+ inline void operator()(uint8_t* ptr) const {
+ UnmapBuffer(ptr);
+ }
+ };
+
+ // Size of the shared buffer.
+ uint64_t size_;
+
+ // Shared buffer when initialized with InitNew.
+ std::unique_ptr<SharedBuffer> buffer_;
+
+ // Handle to shared buffer when initialized with InitFromHandle.
+ ScopedSharedBufferHandle handle_;
+
+ // Pointer to the mapped buffer.
+ std::unique_ptr<uint8_t, MappedBufferDeleter> buffer_ptr_;
+};
+
+} // namespace media
+} // namespace mojo
+
+#endif // MOJO_SERVICES_MEDIA_COMMON_CPP_MAPPED_SHARED_BUFFER_H_
diff --git a/mojo/services/media/common/cpp/shared_media_buffer_allocator.cc b/mojo/services/media/common/cpp/shared_media_buffer_allocator.cc
new file mode 100644
index 0000000..0754203
--- /dev/null
+++ b/mojo/services/media/common/cpp/shared_media_buffer_allocator.cc
@@ -0,0 +1,20 @@
+// Copyright 2015 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 "mojo/services/media/common/cpp/shared_media_buffer_allocator.h"
+
+namespace mojo {
+namespace media {
+
+SharedMediaBufferAllocator::~SharedMediaBufferAllocator() {
+ std::lock_guard<std::mutex> lock(lock_);
+}
+
+void SharedMediaBufferAllocator::OnInit() {
+ std::lock_guard<std::mutex> lock(lock_);
+ fifo_allocator_.Reset(size());
+}
+
+} // namespace media
+} // namespace mojo
diff --git a/mojo/services/media/common/cpp/shared_media_buffer_allocator.h b/mojo/services/media/common/cpp/shared_media_buffer_allocator.h
new file mode 100644
index 0000000..d7b7011
--- /dev/null
+++ b/mojo/services/media/common/cpp/shared_media_buffer_allocator.h
@@ -0,0 +1,67 @@
+// Copyright 2015 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.
+
+#ifndef MOJO_SERVICES_MEDIA_COMMON_CPP_MAPPED_SHARED_MEDIA_BUFFER_ALLOCATOR_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_MAPPED_SHARED_MEDIA_BUFFER_ALLOCATOR_H_
+
+#include <memory>
+#include <mutex> // NOLINT(build/c++11)
+
+#include "mojo/services/media/common/cpp/fifo_allocator.h"
+#include "mojo/services/media/common/cpp/mapped_shared_buffer.h"
+
+namespace mojo {
+namespace media {
+
+// SharedMediaBufferAllocator enhances MappedSharedBuffer by adding allocation
+// semantics (allocate and release) using FifoAllocator. This is useful in media
+// applications in which media buffers are typically allocated and released in
+// a first-allocated, first-released manner. SharedMediaBufferAllocator is
+// thread-safe.
+class SharedMediaBufferAllocator : public MappedSharedBuffer {
+ public:
+ static const uint64_t kNullOffset = FifoAllocator::kNullOffset;
+
+ SharedMediaBufferAllocator() : fifo_allocator_(0) {}
+
+ ~SharedMediaBufferAllocator() override;
+
+ // Allocates a region of the buffer returning an offset. If the requested
+ // region could not be allocated, returns kNullOffset.
+ uint64_t AllocateRegionByOffset(uint64_t size) {
+ std::lock_guard<std::mutex> lock(lock_);
+ return fifo_allocator_.AllocateRegion(size);
+ }
+
+ // Releases a region of the buffer previously allocated by calling
+ // AllocateRegionByOffset.
+ void ReleaseRegionByOffset(uint64_t size, uint64_t offset) {
+ std::lock_guard<std::mutex> lock(lock_);
+ fifo_allocator_.ReleaseRegion(size, offset);
+ }
+
+ // Allocates a region of the buffer returning a pointer. If the requested
+ // region could not be allocated, returns nullptr.
+ void* AllocateRegion(uint64_t size) {
+ return PtrFromOffset(AllocateRegionByOffset(size));
+ }
+
+ // Releases a region of the buffer previously allocated by calling
+ // AllocateRegion.
+ void ReleaseRegion(uint64_t size, void* ptr) {
+ ReleaseRegionByOffset(size, OffsetFromPtr(ptr));
+ }
+
+ protected:
+ void OnInit() override;
+
+ private:
+ mutable std::mutex lock_;
+ FifoAllocator fifo_allocator_;
+};
+
+} // namespace media
+} // namespace mojo
+
+#endif // MOJO_SERVICES_MEDIA_COMMON_CPP_MAPPED_SHARED_MEDIA_BUFFER_ALLOCATOR_H_