blob: f123fd5a5ccaf518da99bf8975591fede12895ff [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 <fuchsia/media/cpp/fidl.h>
#include <memory>
#include <fbl/macros.h>
#include "codec_port.h"
class CodecImpl;
class CodecBufferForTest;
// Core codec representation of a video frame. Different core codecs may have
// very different implementations of this.
// TODO(dustingreen): Have this be a base class that's defined by the
// CodecImpl source_set, and have amlogic-video VideoFrame derive from that base
// class.
// Regardless of codec, these will be managed by shared_ptr<>, because for
// decoder reference frames, shared_ptr<> makes sense.
struct VideoFrame;
// TODO(dustingreen): Support BufferCollection buffers.
// These are 1:1 with Codec buffers, but not necessarily 1:1 with core codec
// buffers.
// The const-ness of a CodecBuffer refers to the fields of the CodecBuffer
// instance, not to the data pointed at by buffer_base().
class CodecBuffer {
// This is the same value as buffer_lifetime_ordinal in StreamProcessor FIDL.
uint64_t lifetime_ordinal() const;
// This matches the buffer_index field of fuchsia::media::Packet when the packet refers to this
// buffer.
uint32_t index() const;
// The vaddr of the start of the mapped VMO for this buffer.
// This will return nullptr if there's no VMO mapping because CPU access isn't
// possible. In that case the vaddr data pointer passed around regarding a
// packet will be an offset into the buffer / VMO, and is only meaningful
// with respect to a CodecBuffer that's also passed alongside.
uint8_t* base() const;
// This will ZX_PANIC() if the buffer hasn't been pinned yet, or if the VMOs
// of the buffers aren't contiguous.
zx_paddr_t physical_base() const;
size_t size() const;
const zx::vmo& vmo() const;
uint64_t offset() const;
const fuchsia::media::StreamBuffer& codec_buffer() const;
// The use of weak_ptr<> here is to emphasize that we don't need shared_ptr<>
// to keep the VideoFrame(s) alive. We'd use a raw pointer here if it weren't
// for needing to convert to a shared_ptr<> to call certain methods that
// expect shared_ptr<>.
// This is marked const because it only mutates a mutable field, which is
// considered mutable because it's about establishing an association between
// video_frame and CodecBuffer after CodecBuffer has been constructed.
void SetVideoFrame(std::weak_ptr<VideoFrame> video_frame) const;
std::weak_ptr<VideoFrame> video_frame() const;
// Unpin is automatic during ~CodecBuffer.
zx_status_t Pin();
bool is_pinned() const;
zx_status_t CacheFlush(uint32_t offset, uint32_t length) const;
friend class CodecImpl;
friend class std::unique_ptr<CodecBuffer>;
friend struct std::default_delete<CodecBuffer>;
friend class CodecBufferForTest;
CodecBuffer(CodecImpl* parent, CodecPort port, fuchsia::media::StreamBuffer buffer,
bool is_secure);
// Maps a page-aligned portion of the VMO including vmo_usable_start to vmo_usable_start +
// vmo_usable_size.
bool Map();
// FakeMap() exists because most CodecAdapter(s) expect to have a CodecBuffer::base() and "data"
// vaddr(s) within the buffer, even when buffers are secure. IIUC, mapping to secure buffer +
// cached policy on the VMO + speculative execution + aarch64 potentially would
// randomly/spuriously fault even if the code never actually touched the mapping. So instead of
// mapping, we use a VMAR to reserve some vaddr space, but without any VMOs backing the VMAR, so
// any actual accesses to any part of the VMAR will fault, and any speculative accesses won't
// spuriuously/randomly fault. We only need one VMAR across all buffers of a BufferCollection, so
// CodecImpl passes in the vaddr of that VMAR here. The fake_map_addr is in keeping with trying
// to minimize the differences between non-secure and secure cases; it's just that we can't have
// an actual mapping to the secure physical pages at the moment. In addition, by not actually
// mapping buffers we can't touch anyway, we presumably save some page table resources.
// The fake_map_addr is used as the a page-aligned base address for a fake mapping. Client code
// must not touch memory at buffer_base() when a fake mapping is in effect, but if client code
// does anyway, that thread will cleanly fault (not get stuck reading, not seem to let a write
// happen, not be reading/writing any arbitrary other data in the process's address space). The
// fake_map_addr vaddr region is guaranteed to have enough vaddr pages to accomodate
// vmo_usable_start % ZX_PAGE_SIZE + vmo_usable_size (so that an access within the bounds of the
// buffer will reliably fault cleanly).
void FakeMap(uint8_t* fake_map_addr);
// The parent CodecImpl instance. Just so we can call parent_->Fail().
// The parent_ CodecImpl out-lives the CodecImpl::Buffer.
CodecImpl* parent_;
CodecPort port_ = kFirstPort;
// This msg still has the live vmo_handle.
fuchsia::media::StreamBuffer buffer_;
// If true, we never ask the kernel to flush the VMO.
bool is_secure_ = false;
// Mutable only in the sense that it's set later than the constructor. The
// association does not switch to a different VideoFrame once set.
mutable std::weak_ptr<VideoFrame> video_frame_;
// This accounts for vmo_usable_start. The content bytes are not part of
// a Buffer instance from a const-ness point of view.
uint8_t* buffer_base_ = nullptr;
// This remains false if fake_map_addr is passed to Map(). Not to be exposed to clients of
// CodecBuffer.
bool is_mapped_ = false;
zx::pmt pinned_;
// We use is_known_contiguous_ to check that physical_base() is only called after Pin() succeeded.
// We check during Pin() that the VMO is really contiguous.
bool is_known_contiguous_ = false;
// This includes the low-order bits of the vmo_usable_start offset, so this is not necessarily
// page-aligned.
zx_paddr_t contiguous_paddr_base_ = {};