Commit 534924a3 authored by Dean Liao's avatar Dean Liao Committed by Commit Bot

media: Use VideoFrameLayout to encapsulate fields in VideoFrame

Use VideoFrameLayout to store format, coded_size, buffer_size
and stride for each buffer. It is because VideoFrame::AllocateMemory()
calculates buffer size which may not meet hardware's need.
VideoFrameLayout is used to record size of buffer and stride the
hardware expected so that VideoFrame::AllocateMemory() can
allocate correct buffer for further use.

BUG=b:110815424
TEST=pass media_unittests

Change-Id: I282dbec1d54019447934a499bc0cd5383ac0f86e
Reviewed-on: https://chromium-review.googlesource.com/1122022
Commit-Queue: Shuo-Peng Liao <deanliao@google.com>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578214}
parent 4fa1b62e
This diff is collapsed.
......@@ -10,9 +10,11 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/md5.h"
#include "base/memory/aligned_memory.h"
......@@ -23,6 +25,7 @@
#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/video_frame_layout.h"
#include "media/base/video_frame_metadata.h"
#include "media/base/video_types.h"
#include "ui/gfx/color_space.h"
......@@ -107,7 +110,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
const gfx::Size& natural_size);
// Creates a new frame in system memory with given parameters. Buffers for the
// frame are allocated but not initialized. The caller most not make
// 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,
......@@ -125,6 +128,16 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
const gfx::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 in |layout| parameter.
static scoped_refptr<VideoFrame> CreateFrameWithLayout(
VideoFrameLayout layout,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
base::TimeDelta timestamp,
bool zero_initialize_memory);
// Wraps a set of native textures with a VideoFrame.
// |mailbox_holders_release_cb| will be called with a sync token as the
// argument when the VideoFrame is to be destroyed.
......@@ -339,16 +352,24 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
// Returns the color space of this frame's content.
gfx::ColorSpace ColorSpace() const;
void set_color_space(const gfx::ColorSpace& color_space);
void set_color_space(const gfx::ColorSpace& color_space) {
color_space_ = color_space;
}
const VideoFrameLayout& layout() const { return layout_; }
VideoPixelFormat format() const { return format_; }
VideoPixelFormat format() const { return layout_.format(); }
StorageType storage_type() const { return storage_type_; }
const gfx::Size& coded_size() const { return coded_size_; }
const gfx::Size& coded_size() const { return layout_.coded_size(); }
const gfx::Rect& visible_rect() const { return visible_rect_; }
const gfx::Size& natural_size() const { return natural_size_; }
int stride(size_t plane) const;
int stride(size_t plane) const {
DCHECK(IsValidPlane(plane, format()));
DCHECK_LT(plane, layout_.num_strides());
return layout_.strides()[plane];
}
// Returns the number of bytes per row and number of rows for a given plane.
//
......@@ -360,8 +381,16 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
// 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;
uint8_t* data(size_t plane);
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
......@@ -475,6 +504,13 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
const gfx::Size& natural_size,
base::TimeDelta timestamp);
// VideoFrameLayout is initialized at caller side.
VideoFrame(VideoFrameLayout layout,
StorageType storage_type,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
base::TimeDelta timestamp);
virtual ~VideoFrame();
// Creates a summary of the configuration settings provided as parameters.
......@@ -491,37 +527,17 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
static gfx::Size DetermineAlignedSize(VideoPixelFormat format,
const gfx::Size& dimensions);
void set_data(size_t plane, uint8_t* ptr);
void set_stride(size_t plane, int stride);
void set_data(size_t plane, uint8_t* ptr) {
DCHECK(IsValidPlane(plane, format()));
DCHECK(ptr);
data_[plane] = ptr;
}
private:
// Clients must use the static factory/wrapping methods to create a new frame.
VideoFrame(VideoPixelFormat format,
StorageType storage_type,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
base::TimeDelta timestamp,
base::ReadOnlySharedMemoryRegion* read_only_region,
base::UnsafeSharedMemoryRegion* unsafe_region,
size_t shared_memory_offset);
VideoFrame(VideoPixelFormat format,
StorageType storage_type,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
base::TimeDelta timestamp,
base::SharedMemoryHandle handle,
size_t shared_memory_offset);
VideoFrame(VideoPixelFormat format,
StorageType storage_type,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
const gpu::MailboxHolder (&mailbox_holders)[kMaxPlanes],
ReleaseMailboxCB mailbox_holder_release_cb,
base::TimeDelta timestamp);
void set_strides(std::vector<int32_t> strides) {
layout_.set_strides(std::move(strides));
}
private:
static scoped_refptr<VideoFrame> WrapExternalStorage(
VideoPixelFormat format,
StorageType storage_type,
......@@ -556,19 +572,27 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
void AllocateMemory(bool zero_initialize_memory);
// Frame format.
const VideoPixelFormat format_;
// Calculates strides if unassigned.
// For the case that plane stride is not assigned, i.e. 0, in the layout_
// object, it calculates strides for each plane based on frame format and
// coded size then writes them back.
void CalculateUnassignedStrides();
// 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).
VideoFrameLayout layout_;
// Storage type for the different planes.
StorageType storage_type_; // TODO(mcasas): make const
// Width and height of the video frame, in pixels. This must include pixel
// data for the whole image; i.e. for YUV formats with subsampled chroma
// planes, in the case that the visible portion of the image does not line up
// on a sample boundary, |coded_size_| must be rounded up appropriately and
// the pixel data provided for the odd pixels.
const gfx::Size coded_size_;
// 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.
......@@ -578,11 +602,6 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
// (|visible_rect_.size()|) with aspect ratio taken into account.
const gfx::Size natural_size_;
// Array of strides for each plane, typically greater or equal to the width
// of the surface divided by the horizontal sampling period. Note that
// strides can be negative.
int32_t strides_[kMaxPlanes];
// 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
......
......@@ -27,10 +27,12 @@ namespace media {
class MEDIA_EXPORT VideoFrameLayout {
public:
// Constructor with strides and buffers' size.
// If strides and buffer_sizes are not assigned, their default value are
// {0, 0, 0, 0} for compatibility with video_frame.cc's original behavior.
VideoFrameLayout(VideoPixelFormat format,
const gfx::Size& coded_size,
std::vector<int32_t> strides = std::vector<int32_t>(),
std::vector<size_t> buffer_sizes = std::vector<size_t>());
std::vector<int32_t> strides = {0, 0, 0, 0},
std::vector<size_t> buffer_sizes = {0, 0, 0, 0});
// Move constructor.
VideoFrameLayout(VideoFrameLayout&&);
......
......@@ -40,8 +40,12 @@ TEST(VideoFrameLayout, ConstructorNoStrideBufferSize) {
EXPECT_EQ(layout.format(), PIXEL_FORMAT_I420);
EXPECT_EQ(layout.coded_size(), coded_size);
EXPECT_EQ(layout.GetTotalBufferSize(), 0u);
EXPECT_EQ(layout.num_strides(), 0u);
EXPECT_EQ(layout.num_buffers(), 0u);
EXPECT_EQ(layout.num_strides(), 4u);
EXPECT_EQ(layout.num_buffers(), 4u);
for (size_t i = 0; i < 4u; ++i) {
EXPECT_EQ(layout.strides()[i], 0);
EXPECT_EQ(layout.buffer_sizes()[i], 0u);
}
}
TEST(VideoFrameLayout, Clone) {
......@@ -129,7 +133,8 @@ TEST(VideoFrameLayout, ToStringNoBufferInfo) {
EXPECT_EQ(layout.ToString(),
"VideoFrameLayout format:PIXEL_FORMAT_NV12 coded_size:320x180 "
"num_buffers:0 buffer_sizes:[] num_strides:0 strides:[]");
"num_buffers:4 buffer_sizes:[0, 0, 0, 0] num_strides:4 "
"strides:[0, 0, 0, 0]");
}
TEST(VideoFrameLayout, SetStrideBufferSize) {
......
......@@ -151,9 +151,12 @@ class VideoEncoderTest
const base::TimeDelta timestamp =
testing_clock_.NowTicks() - first_frame_time_;
scoped_refptr<media::VideoFrame> frame;
if (video_frame_factory_)
if (video_frame_factory_) {
DVLOG(1) << "MaybeCreateFrame";
frame = video_frame_factory_->MaybeCreateFrame(size, timestamp);
}
if (!frame) {
DVLOG(1) << "No VideoFrame, create using VideoFrame::CreateFrame";
frame = media::VideoFrame::CreateFrame(PIXEL_FORMAT_I420, size,
gfx::Rect(size), size, timestamp);
}
......
......@@ -69,6 +69,7 @@ void PopulateVideoFrame(VideoFrame* frame, int start_value) {
// Set Y.
const int height = frame_size.height();
VLOG(1) << "frame num_strides: " << frame->layout().num_strides();
const int stride_y = frame->stride(VideoFrame::kYPlane);
uint8_t* y_plane = frame->data(VideoFrame::kYPlane);
for (int j = 0; j < height; ++j) {
......
......@@ -4,6 +4,9 @@
#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
......@@ -176,9 +179,7 @@ bool MojoSharedBufferVideoFrame::Init(int32_t y_stride,
if (!shared_buffer_mapping_)
return false;
set_stride(kYPlane, y_stride);
set_stride(kUPlane, u_stride);
set_stride(kVPlane, v_stride);
set_strides({y_stride, u_stride, v_stride});
offsets_[kYPlane] = y_offset;
offsets_[kUPlane] = u_offset;
offsets_[kVPlane] = v_offset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment