blob: 13b42ad447acace9ce9a7db783f25d15e7381ca8 [file] [log] [blame]
// Copyright 2016 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.
#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
namespace media {
// static
scoped_refptr<MojoSharedBufferVideoFrame>
MojoSharedBufferVideoFrame::CreateDefaultI420(const gfx::Size& dimensions,
base::TimeDelta timestamp) {
const VideoPixelFormat format = PIXEL_FORMAT_I420;
const gfx::Rect visible_rect(dimensions);
// Since we're allocating memory for the new frame, pad the requested
// size if necessary so that the requested size does line up on sample
// boundaries. See related discussion in VideoFrame::CreateFrameInternal().
const gfx::Size coded_size = DetermineAlignedSize(format, dimensions);
if (!IsValidConfig(format, STORAGE_MOJO_SHARED_BUFFER, coded_size,
visible_rect, dimensions)) {
LOG(DFATAL) << __func__ << " Invalid config. "
<< ConfigToString(format, STORAGE_MOJO_SHARED_BUFFER,
dimensions, visible_rect, dimensions);
return nullptr;
}
// Allocate a shared memory buffer big enough to hold the desired frame.
const size_t allocation_size = VideoFrame::AllocationSize(format, coded_size);
mojo::ScopedSharedBufferHandle handle =
mojo::SharedBufferHandle::Create(allocation_size);
if (!handle.is_valid())
return nullptr;
// Create and initialize the frame. As this is I420 format, the U and V
// planes have samples for each 2x2 block. The memory is laid out as follows:
// - Yplane, full size (each element represents a 1x1 block)
// - Uplane, quarter size (each element represents a 2x2 block)
// - Vplane, quarter size (each element represents a 2x2 block)
DCHECK((coded_size.width() % 2 == 0) && (coded_size.height() % 2 == 0));
return Create(format, coded_size, visible_rect, dimensions, std::move(handle),
allocation_size, 0 /* y_offset */, coded_size.GetArea(),
coded_size.GetArea() * 5 / 4, coded_size.width(),
coded_size.width() / 2, coded_size.width() / 2, timestamp);
}
// static
scoped_refptr<MojoSharedBufferVideoFrame> MojoSharedBufferVideoFrame::Create(
VideoPixelFormat format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
mojo::ScopedSharedBufferHandle handle,
size_t data_size,
size_t y_offset,
size_t u_offset,
size_t v_offset,
int32_t y_stride,
int32_t u_stride,
int32_t v_stride,
base::TimeDelta timestamp) {
if (!IsValidConfig(format, STORAGE_MOJO_SHARED_BUFFER, coded_size,
visible_rect, natural_size)) {
LOG(DFATAL) << __func__ << " Invalid config. "
<< ConfigToString(format, STORAGE_MOJO_SHARED_BUFFER,
coded_size, visible_rect, natural_size);
return nullptr;
}
// Now allocate the frame and initialize it.
scoped_refptr<MojoSharedBufferVideoFrame> frame(
new MojoSharedBufferVideoFrame(format, coded_size, visible_rect,
natural_size, std::move(handle), data_size,
timestamp));
if (!frame->Init(y_stride, u_stride, v_stride, y_offset, u_offset, v_offset))
return nullptr;
return frame;
}
MojoSharedBufferVideoFrame::MojoSharedBufferVideoFrame(
VideoPixelFormat format,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
mojo::ScopedSharedBufferHandle handle,
size_t mapped_size,
base::TimeDelta timestamp)
: VideoFrame(format,
STORAGE_MOJO_SHARED_BUFFER,
coded_size,
visible_rect,
natural_size,
timestamp),
shared_buffer_handle_(std::move(handle)),
shared_buffer_size_(mapped_size) {
DCHECK(shared_buffer_handle_.is_valid());
}
bool MojoSharedBufferVideoFrame::Init(int32_t y_stride,
int32_t u_stride,
int32_t v_stride,
size_t y_offset,
size_t u_offset,
size_t v_offset) {
DCHECK(!shared_buffer_mapping_);
shared_buffer_mapping_ = shared_buffer_handle_->Map(shared_buffer_size_);
if (!shared_buffer_mapping_)
return false;
set_stride(kYPlane, y_stride);
set_stride(kUPlane, u_stride);
set_stride(kVPlane, v_stride);
offsets_[kYPlane] = y_offset;
offsets_[kUPlane] = u_offset;
offsets_[kVPlane] = v_offset;
set_data(kYPlane, shared_buffer_data() + y_offset);
set_data(kUPlane, shared_buffer_data() + u_offset);
set_data(kVPlane, shared_buffer_data() + v_offset);
return true;
}
MojoSharedBufferVideoFrame::~MojoSharedBufferVideoFrame() {
// Call |mojo_shared_buffer_done_cb_| to take ownership of
// |shared_buffer_handle_|.
if (!mojo_shared_buffer_done_cb_.is_null())
mojo_shared_buffer_done_cb_.Run(std::move(shared_buffer_handle_),
shared_buffer_size_);
}
size_t MojoSharedBufferVideoFrame::PlaneOffset(size_t plane) const {
DCHECK(IsValidPlane(plane, format()));
return offsets_[plane];
}
void MojoSharedBufferVideoFrame::SetMojoSharedBufferDoneCB(
const MojoSharedBufferDoneCB& mojo_shared_buffer_done_cb) {
mojo_shared_buffer_done_cb_ = mojo_shared_buffer_done_cb;
}
const mojo::SharedBufferHandle& MojoSharedBufferVideoFrame::Handle() const {
return shared_buffer_handle_.get();
}
size_t MojoSharedBufferVideoFrame::MappedSize() const {
return shared_buffer_size_;
}
} // namespace media