blob: bafd3dec76cec10dfc9e41fa5c4318c3a27ca971 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 SRC_MEDIA_PLAYBACK_MEDIAPLAYER_GRAPH_PAYLOADS_PAYLOAD_BUFFER_H_
#define SRC_MEDIA_PLAYBACK_MEDIAPLAYER_GRAPH_PAYLOADS_PAYLOAD_BUFFER_H_
#include <fbl/recycler.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <fbl/unique_ptr.h>
#include <lib/fit/function.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <memory>
#include "src/lib/fxl/logging.h"
#include "src/media/playback/mediaplayer/graph/payloads/fifo_allocator.h"
namespace media_player {
class VmoPayloadAllocator;
// A VMO used for payload buffers.
class PayloadVmo : public fbl::RefCounted<PayloadVmo> {
public:
// Creates a VMO and wraps it with a |PayloadVmo|. If |bti_handle| is
// provided, the VMO is created with |zx_vmo_create_contiguous|.
// TODO(dalesat): Remove |bti_handle| when the fidl buffer allocator happens.
static fbl::RefPtr<PayloadVmo> Create(uint64_t vmo_size,
const zx::handle* bti_handle = nullptr);
// Creates a |PayloadVmo| that wraps the provided VMO.
static fbl::RefPtr<PayloadVmo> Create(zx::vmo vmo, zx_vm_option_t map_flags);
PayloadVmo(zx::vmo vmo, uint64_t vmo_size, zx_vm_option_t map_flags,
const zx::handle* bti_handle, zx_status_t* status_out);
~PayloadVmo() = default;
// Returns the size of the VMO in bytes.
uint64_t size() const { return size_; }
// Returns the address in process virtual memory where this VMO is mapped, if
// it is mapped, nullptr otherwise.
void* start() const { return vmo_mapper_.start(); }
// The index of this VMO in the allocator's vector of VMOs.
uint32_t index() { return index_; }
// Sets the index of this VMO in the allocator's vector of VMOs.
void SetIndex(uint32_t index) { index_ = index; }
// Returns |start()| offset by |offset| if the VMO is mapped, nullptr
// otherwise.
void* at_offset(uint64_t offset) {
FXL_DCHECK(offset < size_);
if (start() == nullptr) {
return nullptr;
}
return reinterpret_cast<uint8_t*>(start()) + offset;
}
// Returns a reference to the VMO.
zx::vmo& vmo() { return vmo_; }
const zx::vmo& vmo() const { return vmo_; }
// Duplicates the VMO creating a new VMO handle with the specified rights.
zx::vmo Duplicate(zx_rights_t rights);
private:
zx::vmo vmo_;
uint64_t size_;
uint32_t index_;
fzl::VmoMapper vmo_mapper_;
// NOTE: Access to these two fields is serialized using the mutex on the
// owning |VmoPayloadAllocator|.
bool allocated_ = false;
fbl::unique_ptr<FifoAllocator> allocator_;
friend class VmoPayloadAllocator;
};
// A buffer used to hold a packet payload.
//
// A |PayloadBuffer| instance is managed using |fbl::RefPtr| and has an
// associated recycler, which is responsible for freeing the memory that the
// |PayloadBuffer| encapsulates. When the last reference to a |PayloadBuffer|
// is dropped, the recycler is called.
class PayloadBuffer final : public fbl::RefCounted<PayloadBuffer>,
public fbl::Recyclable<PayloadBuffer> {
public:
// All payload buffers must be aligned on |kByteAlignment|-byte boundaries.
static constexpr size_t kByteAlignment = 32;
// Returns the smallest multiple of |kByteAlignment| that is no smaller than
// |size|.
static size_t AlignUp(size_t size) {
return size = (size + kByteAlignment - 1) & ~(kByteAlignment - 1);
}
// Indicates whether |buffer| is aligned to |kByteAlignment| bytes.
static bool IsAligned(void* buffer) {
return (reinterpret_cast<uintptr_t>(buffer) & (kByteAlignment - 1)) == 0;
}
// Function type used to recycle a |PayloadBuffer|. The |PayloadBuffer|
// deletes itself, so the recycler should not attempt to delete it.
using Recycler = fit::function<void(PayloadBuffer*)>;
// Function type used for |AfterRecycling|.
using Action = fit::function<void(PayloadBuffer*)>;
// Creates a new |PayloadBuffer|. |size| may not be 0, and |data| may not be
// nullptr.
static fbl::RefPtr<PayloadBuffer> Create(uint64_t size, void* data,
Recycler recycler);
// Creates a new |PayloadBuffer|. |size| may not be 0, and |data| may not be
// nullptr. |offset_in_vmo| gives the offset of the buffer with respect to
// the start of the VMO. This should be (data - vmo.start()). This
// redundancy is for future support of VMOs that can't be mapped.
// TODO(dalesat): Support null data for payloads that can't be mapped.
static fbl::RefPtr<PayloadBuffer> Create(uint64_t size, void* data,
fbl::RefPtr<PayloadVmo> vmo,
uint64_t offset_in_vmo,
Recycler recycler);
static fbl::RefPtr<PayloadBuffer> CreateWithMalloc(uint64_t size);
~PayloadBuffer();
// Returns the size in bytes of the buffer, which will never be 0.
uint64_t size() const { return size_; }
// Returns a pointer to the buffer, which will never be nullptr.
void* data() const { return data_; }
// Returns the |PayloadVmo| containing the buffer, if the buffer was allocated
// from a VMO, nullptr otherwise.
PayloadVmo* vmo() const { return vmo_.get(); }
// Returns the offset of the data in the VMO, if the buffer was allocated from
// a VMO, zero otherwise.
uint64_t offset() const { return offset_; }
// Returns the ID of this |PayloadBuffer|. This value is set by the party
// that creates the buffer, and its semantics are defined by that party. It
// is intended to identify the buffer and may correspond to the fidl field
// media.StreamPacket.payload_buffer_id or
// mediacodec.CodecBuffer.buffer_index.
uint32_t id() const { return id_; }
// Sets the ID of this |PayloadBuffer|.
void SetId(uint32_t id) { id_ = id; }
// Returns the buffer config of this |PayloadBuffer|. This value is set by the
// party that creates the buffer, and its semantics are defined by that party.
// It is intended to identify the buffer configuration and may correspond to
// the fidl field media.StreamPacket.buffer_config or
// mediacodec.CodecBuffer.buffer_lifetime_ordinal.
uint64_t buffer_config() const { return buffer_config_; }
// Sets the ID of this |PayloadBuffer|.
void SetBufferConfig(uint64_t buffer_config) {
buffer_config_ = buffer_config;
}
// Registers a function to be called after recycling. This method may only
// be called once on a given instance. An |Action| should not hold a reference
// to the |PayloadBuffer|, because this would produce a circular reference,
// and the |PayloadBuffer| would never be released.
void AfterRecycling(Action action);
private:
PayloadBuffer(uint64_t size, void* data, Recycler recycler);
PayloadBuffer(uint64_t size, void* data, fbl::RefPtr<PayloadVmo> vmo,
uint64_t offset, Recycler recycler);
void fbl_recycle();
uint64_t size_;
void* data_;
fbl::RefPtr<PayloadVmo> vmo_;
uint64_t offset_;
uint32_t id_ = 0;
uint64_t buffer_config_ = 0;
Recycler recycler_;
Action after_recycling_;
friend class fbl::Recyclable<PayloadBuffer>;
};
} // namespace media_player
#endif // SRC_MEDIA_PLAYBACK_MEDIAPLAYER_GRAPH_PAYLOADS_PAYLOAD_BUFFER_H_