blob: c82659f16213d18de5e3e12e124a3de22c05a64e [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.
#include "src/media/playback/mediaplayer/graph/payloads/payload_buffer.h"
#include <lib/zx/vmar.h>
#include <cstdlib>
#include <memory>
#include "src/lib/fxl/logging.h"
namespace media_player {
// static
fbl::RefPtr<PayloadVmo> PayloadVmo::Create(uint64_t vmo_size,
const zx::handle* bti_handle) {
FXL_DCHECK(vmo_size != 0);
zx::vmo vmo;
if (bti_handle != nullptr) {
// Create a contiguous VMO. This is a hack that will be removed once the
// FIDL buffer allocator is working an integrated.
zx_status_t status = zx_vmo_create_contiguous(
bti_handle->get(), vmo_size, 0, vmo.reset_and_get_address());
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to create contiguous VMO of size " << vmo_size
<< ", status " << status << ".";
return nullptr;
}
} else {
zx_status_t status = zx::vmo::create(vmo_size, 0, &vmo);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to create VMO of size " << vmo_size
<< ", status " << status << ".";
return nullptr;
}
}
zx_status_t status;
auto result = fbl::MakeRefCounted<PayloadVmo>(
std::move(vmo), vmo_size, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, bti_handle,
&status);
return status == ZX_OK ? result : nullptr;
}
// static
fbl::RefPtr<PayloadVmo> PayloadVmo::Create(zx::vmo vmo,
zx_vm_option_t map_flags) {
uint64_t vmo_size;
zx_status_t status = vmo.get_size(&vmo_size);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to get VMO size.";
return nullptr;
}
auto result = fbl::MakeRefCounted<PayloadVmo>(std::move(vmo), vmo_size,
map_flags, nullptr, &status);
return status == ZX_OK ? result : nullptr;
}
PayloadVmo::PayloadVmo(zx::vmo vmo, uint64_t vmo_size, zx_vm_option_t map_flags,
const zx::handle* bti_handle, zx_status_t* status_out)
: vmo_(std::move(vmo)), size_(vmo_size) {
FXL_DCHECK(vmo_);
FXL_DCHECK(vmo_size != 0);
FXL_DCHECK(status_out != nullptr);
zx_status_t status = vmo_mapper_.Map(vmo_, 0, size_, map_flags, nullptr);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to map VMO, status " << status;
*status_out = status;
return;
}
*status_out = ZX_OK;
}
zx::vmo PayloadVmo::Duplicate(zx_rights_t rights) {
zx::vmo duplicate;
zx_status_t status = vmo_.duplicate(rights, &duplicate);
if (status != ZX_OK) {
FXL_LOG(FATAL) << "Failed to duplicate VMO, status " << status;
}
return duplicate;
}
// static
fbl::RefPtr<PayloadBuffer> PayloadBuffer::Create(uint64_t size, void* data,
Recycler recycler) {
return fbl::AdoptRef(new PayloadBuffer(size, data, std::move(recycler)));
}
// static
fbl::RefPtr<PayloadBuffer> PayloadBuffer::Create(uint64_t size, void* data,
fbl::RefPtr<PayloadVmo> vmo,
uint64_t offset,
Recycler recycler) {
return fbl::AdoptRef(
new PayloadBuffer(size, data, vmo, offset, std::move(recycler)));
}
// static
fbl::RefPtr<PayloadBuffer> PayloadBuffer::CreateWithMalloc(uint64_t size) {
FXL_DCHECK(size > 0);
// TODO: Once we use C++17, std::aligned_alloc should work.
// |aligned_alloc| requires the size to the aligned.
return PayloadBuffer::Create(size,
aligned_alloc(PayloadBuffer::kByteAlignment,
PayloadBuffer::AlignUp(size)),
[](PayloadBuffer* payload_buffer) {
FXL_DCHECK(payload_buffer);
std::free(payload_buffer->data());
// The |PayloadBuffer| deletes itself.
});
}
PayloadBuffer::PayloadBuffer(uint64_t size, void* data, Recycler recycler)
: size_(size), data_(data), recycler_(std::move(recycler)) {
FXL_DCHECK(size_ != 0);
FXL_DCHECK(data_ != nullptr);
FXL_DCHECK(recycler_);
}
PayloadBuffer::PayloadBuffer(uint64_t size, void* data,
fbl::RefPtr<PayloadVmo> vmo,
uint64_t offset_in_vmo, Recycler recycler)
: size_(size),
data_(data),
vmo_(vmo),
offset_(offset_in_vmo),
recycler_(std::move(recycler)) {
FXL_DCHECK(size_ != 0);
FXL_DCHECK(vmo_);
FXL_DCHECK((data_ == nullptr) ||
(reinterpret_cast<uint8_t*>(vmo_->start()) + offset_ ==
reinterpret_cast<uint8_t*>(data_)));
FXL_DCHECK(recycler_);
// TODO(dalesat): Remove this check when we support unmappable VMOs.
FXL_DCHECK(data_ != nullptr);
}
PayloadBuffer::~PayloadBuffer() {
FXL_DCHECK(!recycler_) << "PayloadBuffers must delete themselves.";
}
void PayloadBuffer::AfterRecycling(Action action) {
FXL_DCHECK(!after_recycling_) << "AfterRecycling may only be called once.";
after_recycling_ = std::move(action);
}
void PayloadBuffer::fbl_recycle() {
FXL_DCHECK(recycler_ != nullptr);
recycler_(this);
// This tells the destructor that deletion is being done properly.
recycler_ = nullptr;
if (after_recycling_) {
after_recycling_(this);
}
delete this;
}
} // namespace media_player