426 lines
17 KiB
C++
426 lines
17 KiB
C++
// Copyright (c) 2012 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.
|
|
// Note: ported from Chromium commit head: 602bc8fa60fa
|
|
// Note: only necessary functions are ported.
|
|
// Note: some OS-specific defines have been removed
|
|
// Note: WrapExternalSharedMemory() has been removed in Chromium, but is still
|
|
// present here. Porting the code to a newer version of VideoFrame is not
|
|
// useful, as this is only a temporary step and all usage of VideoFrame will
|
|
// be removed.
|
|
|
|
#ifndef VIDEO_FRAME_H_
|
|
#define VIDEO_FRAME_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "base/callback.h"
|
|
#include "base/logging.h"
|
|
#include "base/macros.h"
|
|
#include "base/memory/aligned_memory.h"
|
|
#include "base/memory/read_only_shared_memory_region.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/memory/shared_memory.h"
|
|
#include "base/memory/shared_memory_handle.h"
|
|
#include "base/memory/unsafe_shared_memory_region.h"
|
|
#include "base/optional.h"
|
|
#include "base/synchronization/lock.h"
|
|
#include "base/thread_annotations.h"
|
|
#include "base/unguessable_token.h"
|
|
#include "rect.h"
|
|
#include "size.h"
|
|
#include "video_frame_layout.h"
|
|
#include "video_frame_metadata.h"
|
|
#include "video_pixel_format.h"
|
|
|
|
#include "base/files/scoped_file.h"
|
|
|
|
namespace media {
|
|
|
|
class VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
|
|
public:
|
|
enum {
|
|
kFrameSizeAlignment = 16,
|
|
kFrameSizePadding = 16,
|
|
|
|
kFrameAddressAlignment = VideoFrameLayout::kBufferAddressAlignment
|
|
};
|
|
|
|
enum {
|
|
kMaxPlanes = 4,
|
|
|
|
kYPlane = 0,
|
|
kARGBPlane = kYPlane,
|
|
kUPlane = 1,
|
|
kUVPlane = kUPlane,
|
|
kVPlane = 2,
|
|
kAPlane = 3,
|
|
};
|
|
|
|
// Defines the pixel storage type. Differentiates between directly accessible
|
|
// |data_| and pixels that are only indirectly accessible and not via mappable
|
|
// memory.
|
|
// Note that VideoFrames of any StorageType can also have Texture backing,
|
|
// with "classical" GPU Driver-only textures identified as STORAGE_OPAQUE.
|
|
enum StorageType {
|
|
STORAGE_UNKNOWN = 0,
|
|
STORAGE_OPAQUE = 1, // We don't know how VideoFrame's pixels are stored.
|
|
STORAGE_UNOWNED_MEMORY = 2, // External, non owned data pointers.
|
|
STORAGE_OWNED_MEMORY = 3, // VideoFrame has allocated its own data buffer.
|
|
STORAGE_SHMEM = 4, // Pixels are backed by Shared Memory.
|
|
// TODO(mcasas): Consider turning this type into STORAGE_NATIVE
|
|
// based on the idea of using this same enum value for both DMA
|
|
// buffers on Linux and CVPixelBuffers on Mac (which currently use
|
|
// STORAGE_UNOWNED_MEMORY) and handle it appropriately in all cases.
|
|
STORAGE_DMABUFS = 5, // Each plane is stored into a DmaBuf.
|
|
STORAGE_MOJO_SHARED_BUFFER = 6,
|
|
STORAGE_LAST = STORAGE_MOJO_SHARED_BUFFER,
|
|
};
|
|
|
|
// Call prior to CreateFrame to ensure validity of frame configuration. Called
|
|
// automatically by VideoDecoderConfig::IsValidConfig().
|
|
static bool IsValidConfig(VideoPixelFormat format,
|
|
StorageType storage_type,
|
|
const Size& coded_size,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size);
|
|
|
|
// Creates a new frame in system memory with given parameters. Buffers for the
|
|
// frame are allocated but not initialized. The caller must not make
|
|
// assumptions about the actual underlying size(s), but check the returned
|
|
// VideoFrame instead.
|
|
static scoped_refptr<VideoFrame> CreateFrame(VideoPixelFormat format,
|
|
const Size& coded_size,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size,
|
|
base::TimeDelta timestamp);
|
|
|
|
// Creates a new frame in system memory with given parameters. Buffers for the
|
|
// frame are allocated but not initialized. The caller should specify the
|
|
// physical buffer size and strides if needed in |layout| parameter.
|
|
static scoped_refptr<VideoFrame> CreateFrameWithLayout(
|
|
const VideoFrameLayout& layout,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size,
|
|
base::TimeDelta timestamp,
|
|
bool zero_initialize_memory);
|
|
|
|
// Legacy wrapping of old SharedMemoryHandle objects. Deprecated, use one of
|
|
// the shared memory region wrappers above instead.
|
|
static scoped_refptr<VideoFrame> WrapExternalSharedMemory(
|
|
VideoPixelFormat format,
|
|
const Size& coded_size,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size,
|
|
uint8_t* data,
|
|
size_t data_size,
|
|
base::SharedMemoryHandle handle,
|
|
size_t shared_memory_offset,
|
|
base::TimeDelta timestamp);
|
|
|
|
// Creates a frame which indicates end-of-stream.
|
|
static scoped_refptr<VideoFrame> CreateEOSFrame();
|
|
|
|
static size_t NumPlanes(VideoPixelFormat format);
|
|
|
|
// Returns the required allocation size for a (tightly packed) frame of the
|
|
// given coded size and format.
|
|
static size_t AllocationSize(VideoPixelFormat format, const Size& coded_size);
|
|
|
|
// Returns the plane Size (in bytes) for a plane of the given coded size
|
|
// and format.
|
|
static Size PlaneSize(VideoPixelFormat format,
|
|
size_t plane,
|
|
const Size& coded_size);
|
|
|
|
// Returns horizontal bits per pixel for given |plane| and |format|.
|
|
static int PlaneHorizontalBitsPerPixel(VideoPixelFormat format, size_t plane);
|
|
|
|
// Returns bits per pixel for given |plane| and |format|.
|
|
static int PlaneBitsPerPixel(VideoPixelFormat format, size_t plane);
|
|
|
|
// Returns the number of bytes per row for the given plane, format, and width.
|
|
// The width may be aligned to format requirements.
|
|
static size_t RowBytes(size_t plane, VideoPixelFormat format, int width);
|
|
|
|
// Returns the number of bytes per element for given |plane| and |format|.
|
|
static int BytesPerElement(VideoPixelFormat format, size_t plane);
|
|
|
|
// Calculates strides for each plane based on |format| and |coded_size|.
|
|
static std::vector<int32_t> ComputeStrides(VideoPixelFormat format,
|
|
const Size& coded_size);
|
|
|
|
// Returns the number of rows for the given plane, format, and height.
|
|
// The height may be aligned to format requirements.
|
|
static size_t Rows(size_t plane, VideoPixelFormat format, int height);
|
|
|
|
// Returns the number of columns for the given plane, format, and width.
|
|
// The width may be aligned to format requirements.
|
|
static size_t Columns(size_t plane, VideoPixelFormat format, int width);
|
|
|
|
// Returns true if |frame| is accesible mapped in the VideoFrame memory space.
|
|
// static
|
|
static bool IsStorageTypeMappable(VideoFrame::StorageType storage_type);
|
|
|
|
// Returns true if |frame| is accessible and mapped in the VideoFrame memory
|
|
// space. If false, clients should refrain from accessing data(),
|
|
// visible_data() etc.
|
|
bool IsMappable() const;
|
|
|
|
const VideoFrameLayout& layout() const { return layout_; }
|
|
|
|
VideoPixelFormat format() const { return layout_.format(); }
|
|
StorageType storage_type() const { return storage_type_; }
|
|
|
|
// The full dimensions of the video frame data.
|
|
const Size& coded_size() const { return layout_.coded_size(); }
|
|
// A subsection of [0, 0, coded_size().width(), coded_size.height()]. This
|
|
// can be set to "soft-apply" a cropping. It determines the pointers into
|
|
// the data returned by visible_data().
|
|
const Rect& visible_rect() const { return visible_rect_; }
|
|
// Specifies that the |visible_rect| section of the frame is supposed to be
|
|
// scaled to this size when being presented. This can be used to represent
|
|
// anamorphic frames, or to "soft-apply" any custom scaling.
|
|
const Size& natural_size() const { return natural_size_; }
|
|
|
|
int stride(size_t plane) const {
|
|
DCHECK(IsValidPlane(plane, format()));
|
|
DCHECK_LT(plane, layout_.num_planes());
|
|
return layout_.planes()[plane].stride;
|
|
}
|
|
|
|
// Returns the number of bytes per row and number of rows for a given plane.
|
|
//
|
|
// As opposed to stride(), row_bytes() refers to the bytes representing
|
|
// frame data scanlines (coded_size.width() pixels, without stride padding).
|
|
int row_bytes(size_t plane) const;
|
|
int rows(size_t plane) const;
|
|
|
|
// Returns pointer to the buffer for a given plane, if this is an
|
|
// IsMappable() frame type. The memory is owned by VideoFrame object and must
|
|
// not be freed by the caller.
|
|
const uint8_t* data(size_t plane) const {
|
|
DCHECK(IsValidPlane(plane, format()));
|
|
DCHECK(IsMappable());
|
|
return data_[plane];
|
|
}
|
|
uint8_t* data(size_t plane) {
|
|
DCHECK(IsValidPlane(plane, format()));
|
|
DCHECK(IsMappable());
|
|
return data_[plane];
|
|
}
|
|
|
|
// Returns pointer to the data in the visible region of the frame, for
|
|
// IsMappable() storage types. The returned pointer is offsetted into the
|
|
// plane buffer specified by visible_rect().origin(). Memory is owned by
|
|
// VideoFrame object and must not be freed by the caller.
|
|
const uint8_t* visible_data(size_t plane) const;
|
|
uint8_t* visible_data(size_t plane);
|
|
|
|
// Returns a pointer to the read-only shared-memory region, if present.
|
|
base::ReadOnlySharedMemoryRegion* read_only_shared_memory_region() const;
|
|
|
|
// Returns a pointer to the unsafe shared memory handle, if present.
|
|
base::UnsafeSharedMemoryRegion* unsafe_shared_memory_region() const;
|
|
|
|
// Returns the legacy SharedMemoryHandle, if present.
|
|
base::SharedMemoryHandle shared_memory_handle() const;
|
|
|
|
// Returns the offset into the shared memory where the frame data begins.
|
|
size_t shared_memory_offset() const;
|
|
|
|
// Returns a vector containing the backing DmaBufs for this frame. The number
|
|
// of returned DmaBufs will be equal or less than the number of planes of
|
|
// the frame. If there are less, this means that the last FD contains the
|
|
// remaining planes.
|
|
// Note that the returned FDs are still owned by the VideoFrame. This means
|
|
// that the caller shall not close them, or use them after the VideoFrame is
|
|
// destroyed. For such use cases, use media::DuplicateFDs() to obtain your
|
|
// own copy of the FDs.
|
|
const std::vector<base::ScopedFD>& DmabufFds() const;
|
|
|
|
// Returns true if |frame| has DmaBufs.
|
|
bool HasDmaBufs() const;
|
|
|
|
void AddReadOnlySharedMemoryRegion(base::ReadOnlySharedMemoryRegion* region);
|
|
void AddUnsafeSharedMemoryRegion(base::UnsafeSharedMemoryRegion* region);
|
|
|
|
// Legacy, use one of the Add*SharedMemoryRegion methods above instead.
|
|
void AddSharedMemoryHandle(base::SharedMemoryHandle handle);
|
|
|
|
// Adds a callback to be run when the VideoFrame is about to be destroyed.
|
|
// The callback may be run from ANY THREAD, and so it is up to the client to
|
|
// ensure thread safety. Although read-only access to the members of this
|
|
// VideoFrame is permitted while the callback executes (including
|
|
// VideoFrameMetadata), clients should not assume the data pointers are
|
|
// valid.
|
|
void AddDestructionObserver(base::OnceClosure callback);
|
|
|
|
// Returns a dictionary of optional metadata. This contains information
|
|
// associated with the frame that downstream clients might use for frame-level
|
|
// logging, quality/performance optimizations, signaling, etc.
|
|
//
|
|
// TODO(miu): Move some of the "extra" members of VideoFrame (below) into
|
|
// here as a later clean-up step.
|
|
const VideoFrameMetadata* metadata() const { return &metadata_; }
|
|
VideoFrameMetadata* metadata() { return &metadata_; }
|
|
|
|
// The time span between the current frame and the first frame of the stream.
|
|
// This is the media timestamp, and not the reference time.
|
|
// See VideoFrameMetadata::REFERENCE_TIME for details.
|
|
base::TimeDelta timestamp() const { return timestamp_; }
|
|
void set_timestamp(base::TimeDelta timestamp) { timestamp_ = timestamp; }
|
|
|
|
// Returns a human-readable string describing |*this|.
|
|
std::string AsHumanReadableString();
|
|
|
|
// Unique identifier for this video frame; generated at construction time and
|
|
// guaranteed to be unique within a single process.
|
|
int unique_id() const { return unique_id_; }
|
|
|
|
// Returns the number of bits per channel.
|
|
size_t BitDepth() const;
|
|
|
|
protected:
|
|
friend class base::RefCountedThreadSafe<VideoFrame>;
|
|
|
|
// Clients must use the static factory/wrapping methods to create a new frame.
|
|
// Derived classes should create their own factory/wrapping methods, and use
|
|
// this constructor to do basic initialization.
|
|
VideoFrame(const VideoFrameLayout& layout,
|
|
StorageType storage_type,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size,
|
|
base::TimeDelta timestamp);
|
|
|
|
virtual ~VideoFrame();
|
|
|
|
// Creates a summary of the configuration settings provided as parameters.
|
|
static std::string ConfigToString(const VideoPixelFormat format,
|
|
const VideoFrame::StorageType storage_type,
|
|
const Size& coded_size,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size);
|
|
|
|
// Returns true if |plane| is a valid plane index for the given |format|.
|
|
static bool IsValidPlane(size_t plane, VideoPixelFormat format);
|
|
|
|
// Returns |dimensions| adjusted to appropriate boundaries based on |format|.
|
|
static Size DetermineAlignedSize(VideoPixelFormat format,
|
|
const Size& dimensions);
|
|
|
|
void set_data(size_t plane, uint8_t* ptr) {
|
|
DCHECK(IsValidPlane(plane, format()));
|
|
DCHECK(ptr);
|
|
data_[plane] = ptr;
|
|
}
|
|
|
|
private:
|
|
static scoped_refptr<VideoFrame> WrapExternalStorage(
|
|
StorageType storage_type,
|
|
const VideoFrameLayout& layout,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size,
|
|
uint8_t* data,
|
|
size_t data_size,
|
|
base::TimeDelta timestamp,
|
|
base::ReadOnlySharedMemoryRegion* read_only_region,
|
|
base::UnsafeSharedMemoryRegion* unsafe_region,
|
|
base::SharedMemoryHandle handle,
|
|
size_t data_offset);
|
|
|
|
static scoped_refptr<VideoFrame> CreateFrameInternal(
|
|
VideoPixelFormat format,
|
|
const Size& coded_size,
|
|
const Rect& visible_rect,
|
|
const Size& natural_size,
|
|
base::TimeDelta timestamp,
|
|
bool zero_initialize_memory);
|
|
|
|
bool SharedMemoryUninitialized();
|
|
|
|
// Returns true if |plane| is a valid plane index for the given |format|.
|
|
static bool IsValidPlane(VideoPixelFormat format, size_t plane);
|
|
|
|
// Returns the pixel size of each subsample for a given |plane| and |format|.
|
|
// E.g. 2x2 for the U-plane in PIXEL_FORMAT_I420.
|
|
static Size SampleSize(VideoPixelFormat format, size_t plane);
|
|
|
|
// Return the alignment for the whole frame, calculated as the max of the
|
|
// alignment for each individual plane.
|
|
static Size CommonAlignment(VideoPixelFormat format);
|
|
|
|
void AllocateMemory(bool zero_initialize_memory);
|
|
|
|
// Calculates plane size.
|
|
// It first considers buffer size layout_ object provides. If layout's
|
|
// number of buffers equals to number of planes, and buffer size is assigned
|
|
// (non-zero), it returns buffers' size.
|
|
// Otherwise, it uses the first (num_buffers - 1) assigned buffers' size as
|
|
// plane size. Then for the rest unassigned planes, calculates their size
|
|
// based on format, coded size and stride for the plane.
|
|
std::vector<size_t> CalculatePlaneSize() const;
|
|
|
|
// VideFrameLayout (includes format, coded_size, and strides).
|
|
const VideoFrameLayout layout_;
|
|
|
|
// Storage type for the different planes.
|
|
StorageType storage_type_; // TODO(mcasas): make const
|
|
|
|
// Width, height, and offsets of the visible portion of the video frame. Must
|
|
// be a subrect of |coded_size_|. Can be odd with respect to the sample
|
|
// boundaries, e.g. for formats with subsampled chroma.
|
|
const Rect visible_rect_;
|
|
|
|
// Width and height of the visible portion of the video frame
|
|
// (|visible_rect_.size()|) with aspect ratio taken into account.
|
|
const Size natural_size_;
|
|
|
|
// Array of data pointers to each plane.
|
|
// TODO(mcasas): we don't know on ctor if we own |data_| or not. Change
|
|
// to std::unique_ptr<uint8_t, AlignedFreeDeleter> after refactoring
|
|
// VideoFrame.
|
|
uint8_t* data_[kMaxPlanes];
|
|
|
|
// Shared memory handle and associated offset inside it, if this frame is a
|
|
// STORAGE_SHMEM one. Pointers to unowned shared memory regions. At most one
|
|
// of the memory regions will be set.
|
|
base::ReadOnlySharedMemoryRegion* read_only_shared_memory_region_ = nullptr;
|
|
base::UnsafeSharedMemoryRegion* unsafe_shared_memory_region_ = nullptr;
|
|
|
|
// Legacy handle.
|
|
base::SharedMemoryHandle shared_memory_handle_;
|
|
|
|
// If this is a STORAGE_SHMEM frame, the offset of the data within the shared
|
|
// memory.
|
|
size_t shared_memory_offset_;
|
|
|
|
class DmabufHolder;
|
|
|
|
// Dmabufs for the frame, used when storage is STORAGE_DMABUFS. Size is either
|
|
// equal or less than the number of planes of the frame. If it is less, then
|
|
// the memory area represented by the last FD contains the remaining planes.
|
|
std::vector<base::ScopedFD> dmabuf_fds_;
|
|
|
|
std::vector<base::OnceClosure> done_callbacks_;
|
|
|
|
base::TimeDelta timestamp_;
|
|
|
|
VideoFrameMetadata metadata_;
|
|
|
|
// Generated at construction time.
|
|
const int unique_id_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(VideoFrame);
|
|
};
|
|
|
|
} // namespace media
|
|
|
|
#endif // VIDEO_FRAME_H_
|